Compare commits

..

19 Commits

Author SHA1 Message Date
21c336360c revert 2024-09-06 10:40:45 +04:00
fee34703bd revert back 2024-09-06 10:33:39 +04:00
a92676d6a4 revert back to dev 2024-09-06 10:32:02 +04:00
8c5cf2c04e dialog 2024-09-06 10:25:54 +04:00
1f02f66916 changed stack to column 2024-09-06 10:20:52 +04:00
3ea089425c revert back change 2024-09-06 10:07:14 +04:00
77d2f54352 revert back dev 2024-09-02 13:38:49 +04:00
cff66bb653 revert back to dev 2024-09-02 13:35:25 +04:00
022ba53f5d Revert back to dev 2024-09-02 13:34:16 +04:00
bf69399af2 Merge remote-tracking branch 'origin/dev' into bugfix/SP-292 2024-09-02 13:27:08 +04:00
a72fc0b466 Added dialogue for success message 2024-09-02 13:25:58 +04:00
df13840a65 asset added of success icon 2024-09-02 13:25:33 +04:00
e63bf2a2c2 Merge pull request #47 from SyncrowIOT/bugfix/SP-286
fix: Shows only one error at a time for password validation error
2024-09-02 09:05:03 +04:00
b3bb0b9eea fix: Correct error message and improve consistency in passwordValidator 2024-08-29 16:37:49 +04:00
032a28d47a setting up the dependencies 2024-08-29 15:54:27 +04:00
dcc98445d7 Implemented smart door animation 2024-08-26 16:45:50 +03:00
611c515173 Updated icons and bug fixes 2024-08-21 16:10:57 +03:00
e733dd9230 Updated the build number 2024-08-12 17:39:02 +03:00
8e104aeea7 Read devices status from Firebase realtime database 2024-08-12 12:32:20 +03:00
67 changed files with 761 additions and 409 deletions

View File

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

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,46 +1,54 @@
PODS:
- device_info_plus (0.0.1):
- Flutter
- Firebase/Analytics (10.20.0):
- Firebase/Analytics (10.25.0):
- Firebase/Core
- Firebase/Core (10.20.0):
- Firebase/Core (10.25.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 10.20.0)
- Firebase/CoreOnly (10.20.0):
- FirebaseCore (= 10.20.0)
- Firebase/Crashlytics (10.20.0):
- FirebaseAnalytics (~> 10.25.0)
- Firebase/CoreOnly (10.25.0):
- FirebaseCore (= 10.25.0)
- Firebase/Crashlytics (10.25.0):
- Firebase/CoreOnly
- FirebaseCrashlytics (~> 10.20.0)
- FirebaseCrashlytics (~> 10.25.0)
- Firebase/Database (10.25.0):
- Firebase/CoreOnly
- FirebaseDatabase (~> 10.25.0)
- firebase_analytics (10.8.7):
- Firebase/Analytics (= 10.20.0)
- Firebase/Analytics (= 10.25.0)
- firebase_core
- Flutter
- firebase_core (2.25.5):
- Firebase/CoreOnly (= 10.20.0)
- firebase_core (2.32.0):
- Firebase/CoreOnly (= 10.25.0)
- Flutter
- firebase_crashlytics (3.4.16):
- Firebase/Crashlytics (= 10.20.0)
- Firebase/Crashlytics (= 10.25.0)
- firebase_core
- Flutter
- FirebaseAnalytics (10.20.0):
- FirebaseAnalytics/AdIdSupport (= 10.20.0)
- firebase_database (10.5.7):
- Firebase/Database (= 10.25.0)
- firebase_core
- Flutter
- FirebaseAnalytics (10.25.0):
- FirebaseAnalytics/AdIdSupport (= 10.25.0)
- FirebaseCore (~> 10.0)
- FirebaseInstallations (~> 10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
- GoogleUtilities/MethodSwizzler (~> 7.11)
- GoogleUtilities/Network (~> 7.11)
- "GoogleUtilities/NSData+zlib (~> 7.11)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseAnalytics/AdIdSupport (10.20.0):
- nanopb (< 2.30911.0, >= 2.30908.0)
- FirebaseAnalytics/AdIdSupport (10.25.0):
- FirebaseCore (~> 10.0)
- FirebaseInstallations (~> 10.0)
- GoogleAppMeasurement (= 10.20.0)
- GoogleAppMeasurement (= 10.25.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
- GoogleUtilities/MethodSwizzler (~> 7.11)
- GoogleUtilities/Network (~> 7.11)
- "GoogleUtilities/NSData+zlib (~> 7.11)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseCore (10.20.0):
- nanopb (< 2.30911.0, >= 2.30908.0)
- FirebaseAppCheckInterop (10.29.0)
- FirebaseCore (10.25.0):
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.12)
- GoogleUtilities/Logger (~> 7.12)
@ -48,19 +56,27 @@ PODS:
- FirebaseCore (~> 10.0)
- FirebaseCoreInternal (10.29.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)"
- FirebaseCrashlytics (10.20.0):
- FirebaseCrashlytics (10.25.0):
- FirebaseCore (~> 10.5)
- FirebaseInstallations (~> 10.0)
- FirebaseRemoteConfigInterop (~> 10.23)
- FirebaseSessions (~> 10.5)
- GoogleDataTransport (~> 9.2)
- GoogleUtilities/Environment (~> 7.8)
- nanopb (< 2.30910.0, >= 2.30908.0)
- nanopb (< 2.30911.0, >= 2.30908.0)
- PromisesObjC (~> 2.1)
- FirebaseDatabase (10.25.0):
- FirebaseAppCheckInterop (~> 10.17)
- FirebaseCore (~> 10.0)
- FirebaseSharedSwift (~> 10.0)
- GoogleUtilities/UserDefaults (~> 7.13)
- leveldb-library (~> 1.22)
- FirebaseInstallations (10.29.0):
- FirebaseCore (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- PromisesObjC (~> 2.1)
- FirebaseRemoteConfigInterop (10.29.0)
- FirebaseSessions (10.29.0):
- FirebaseCore (~> 10.5)
- FirebaseCoreExtension (~> 10.0)
@ -70,31 +86,32 @@ PODS:
- GoogleUtilities/UserDefaults (~> 7.13)
- nanopb (< 2.30911.0, >= 2.30908.0)
- PromisesSwift (~> 2.1)
- FirebaseSharedSwift (10.29.0)
- Flutter (1.0.0)
- flutter_localization (0.0.1):
- Flutter
- flutter_secure_storage (6.0.0):
- Flutter
- GoogleAppMeasurement (10.20.0):
- GoogleAppMeasurement/AdIdSupport (= 10.20.0)
- GoogleAppMeasurement (10.25.0):
- GoogleAppMeasurement/AdIdSupport (= 10.25.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
- GoogleUtilities/MethodSwizzler (~> 7.11)
- GoogleUtilities/Network (~> 7.11)
- "GoogleUtilities/NSData+zlib (~> 7.11)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- GoogleAppMeasurement/AdIdSupport (10.20.0):
- GoogleAppMeasurement/WithoutAdIdSupport (= 10.20.0)
- nanopb (< 2.30911.0, >= 2.30908.0)
- GoogleAppMeasurement/AdIdSupport (10.25.0):
- GoogleAppMeasurement/WithoutAdIdSupport (= 10.25.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
- GoogleUtilities/MethodSwizzler (~> 7.11)
- GoogleUtilities/Network (~> 7.11)
- "GoogleUtilities/NSData+zlib (~> 7.11)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- GoogleAppMeasurement/WithoutAdIdSupport (10.20.0):
- nanopb (< 2.30911.0, >= 2.30908.0)
- GoogleAppMeasurement/WithoutAdIdSupport (10.25.0):
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
- GoogleUtilities/MethodSwizzler (~> 7.11)
- GoogleUtilities/Network (~> 7.11)
- "GoogleUtilities/NSData+zlib (~> 7.11)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- nanopb (< 2.30911.0, >= 2.30908.0)
- GoogleDataTransport (9.4.1):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30911.0, >= 2.30908.0)
@ -129,11 +146,12 @@ PODS:
- GoogleUtilities/Privacy
- image_picker_ios (0.0.1):
- Flutter
- nanopb (2.30909.1):
- nanopb/decode (= 2.30909.1)
- nanopb/encode (= 2.30909.1)
- nanopb/decode (2.30909.1)
- nanopb/encode (2.30909.1)
- leveldb-library (1.22.5)
- nanopb (2.30910.0):
- nanopb/decode (= 2.30910.0)
- nanopb/encode (= 2.30910.0)
- nanopb/decode (2.30910.0)
- nanopb/encode (2.30910.0)
- onesignal_flutter (5.2.0):
- Flutter
- OneSignalXCFramework (= 5.2.0)
@ -207,6 +225,7 @@ DEPENDENCIES:
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
- firebase_database (from `.symlinks/plugins/firebase_database/ios`)
- Flutter (from `Flutter`)
- flutter_localization (from `.symlinks/plugins/flutter_localization/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
@ -223,15 +242,20 @@ SPEC REPOS:
trunk:
- Firebase
- FirebaseAnalytics
- FirebaseAppCheckInterop
- FirebaseCore
- FirebaseCoreExtension
- FirebaseCoreInternal
- FirebaseCrashlytics
- FirebaseDatabase
- FirebaseInstallations
- FirebaseRemoteConfigInterop
- FirebaseSessions
- FirebaseSharedSwift
- GoogleAppMeasurement
- GoogleDataTransport
- GoogleUtilities
- leveldb-library
- nanopb
- OneSignalXCFramework
- PromisesObjC
@ -246,6 +270,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_core/ios"
firebase_crashlytics:
:path: ".symlinks/plugins/firebase_crashlytics/ios"
firebase_database:
:path: ".symlinks/plugins/firebase_database/ios"
Flutter:
:path: Flutter
flutter_localization:
@ -271,25 +297,31 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
Firebase: 10c8cb12fb7ad2ae0c09ffc86cd9c1ab392a0031
firebase_analytics: 2c1c3057d5da3bd3aab819f7e6ee153a4e46c59e
firebase_core: c8628c7ce80f79439149549052bff22f6784fbf5
firebase_crashlytics: 012078b4eec6fc9716f97ba3da0f0e44a04e95b1
FirebaseAnalytics: a2731bf3670747ce8f65368b118d18aa8e368246
FirebaseCore: 28045c1560a2600d284b9c45a904fe322dc890b6
Firebase: 0312a2352584f782ea56f66d91606891d4607f06
firebase_analytics: 3a9263fedec72970e6bd30a7132bbdd386de2c14
firebase_core: a626d00494efa398e7c54f25f1454a64c8abf197
firebase_crashlytics: 0b7cb41f5fb3b6889d0fb408cfce3cc7a4247061
firebase_database: 2713033e426b176d4fe5e7195f3d19aa1b549a91
FirebaseAnalytics: ec00fe8b93b41dc6fe4a28784b8e51da0647a248
FirebaseAppCheckInterop: 6a1757cfd4067d8e00fccd14fcc1b8fd78cfac07
FirebaseCore: 7ec4d0484817f12c3373955bc87762d96842d483
FirebaseCoreExtension: 705ca5b14bf71d2564a0ddc677df1fc86ffa600f
FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934
FirebaseCrashlytics: 81530595edb6d99f1918f723a6c33766a24a4c86
FirebaseCrashlytics: 4b96efb0ce73b38b2a85e8b8bd1bd8f63f09d015
FirebaseDatabase: faa489a42f5f868d23a55dd442d6e2099348458e
FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd
FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d
FirebaseSessions: dbd14adac65ce996228652c1fc3a3f576bdf3ecc
FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_localization: f43b18844a2b3d2c71fd64f04ffd6b1e64dd54d4
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
GoogleAppMeasurement: bb3c564c3efb933136af0e94899e0a46167466a8
GoogleAppMeasurement: 9abf64b682732fed36da827aa2a68f0221fd2356
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
leveldb-library: e8eadf9008a61f9e1dde3978c086d2b6d9b9dc28
nanopb: 438bc412db1928dac798aa6fd75726007be04262
onesignal_flutter: 5ce68a29861960168e81101cb1bd685d264361de
OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c

View File

@ -514,8 +514,8 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
@ -524,7 +524,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
MARKETING_VERSION = 1.0.2;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -706,8 +706,8 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
@ -716,7 +716,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
MARKETING_VERSION = 1.0.2;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -736,8 +736,8 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = "";
CURRENT_PROJECT_VERSION = 20;
DEVELOPMENT_TEAM = 48V27SBR8J;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
@ -746,7 +746,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
MARKETING_VERSION = 1.0.2;
PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -1,115 +1,115 @@
{
"images" : [
{
"filename" : "logo-20@2x.png",
"filename" : "Syncrow Icon-20@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "logo-20@3x.png",
"filename" : "Syncrow Icon-20@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "logo-29.png",
"filename" : "Syncrow Icon-29.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "logo-29@2x.png",
"filename" : "Syncrow Icon-29@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "logo-29@3x.png",
"filename" : "Syncrow Icon-29@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "logo-40@2x.png",
"filename" : "Syncrow Icon-40@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "logo-40@3x.png",
"filename" : "Syncrow Icon-40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "logo-60@2x.png",
"filename" : "Syncrow Icon-60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "logo-60@3x.png",
"filename" : "Syncrow Icon-60@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "logo-20.png",
"filename" : "Syncrow Icon-20.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"filename" : "logo-20@2x 1.png",
"filename" : "Syncrow Icon-20@2x 1.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "logo-29 1.png",
"filename" : "Syncrow Icon-29 1.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "logo-29@2x 1.png",
"filename" : "Syncrow Icon-29@2x 1.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "logo-40.png",
"filename" : "Syncrow Icon-40.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"filename" : "logo-40@2x 1.png",
"filename" : "Syncrow Icon-40@2x 1.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "logo-76.png",
"filename" : "Syncrow Icon-76.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "logo-76@2x.png",
"filename" : "Syncrow Icon-76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "logo-83.5@2x.png",
"filename" : "Syncrow Icon-83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "logo-1024.png",
"filename" : "Syncrow Icon-1024.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -11,10 +11,7 @@ import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdo
import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/features/dashboard/view/dashboard_view.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/model/room_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
@ -22,10 +19,7 @@ import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_b
import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/view/create_scene_view.dart';
import 'package:syncrow_app/features/scene/view/scene_tasks_view.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
@ -33,10 +27,8 @@ import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
part 'home_state.dart';
@ -161,7 +153,7 @@ class HomeCubit extends Cubit<HomeState> {
}
_sendSubscriptionId() async {
String? subscriptionId = OneSignal.User.pushSubscription.id ?? '';
// String? subscriptionId = OneSignal.User.pushSubscription.id ?? '';
//TODO send the subscription id to BE
}

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
@ -59,18 +58,30 @@ class AuthCubit extends Cubit<AuthState> {
/////////////////////////////////////VALIDATORS/////////////////////////////////////
String? passwordValidator(String? value) {
if (value != null) {
if (value.isEmpty) {
return 'Please enter your password';
}
if (value.isNotEmpty) {
if (!RegExp(
r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!"#$%&()*+,-./:;<=>?@[\]^_`{|}~])[A-Za-z\d!"#$%&()*+,-./:;<=>?@[\]^_`{|}~]{8,}$')
.hasMatch(value)) {
return 'Password must contain at least:\n - one uppercase letter.\n - one lowercase letter.\n - one number. \n - special character';
}
}
if (value == null || value.isEmpty) {
return "Please enter your password";
}
if (value.length < 8) {
return 'Password must be at least 8 characters long';
}
if (!RegExp(r'[a-z]').hasMatch(value)) {
return 'Password must contain at least one lowercase letter';
}
if (!RegExp(r'[A-Z]').hasMatch(value)) {
return 'Password must contain at least one uppercase letter';
}
if (!RegExp(r'\d').hasMatch(value)) {
return 'Password must contain at least one number';
}
if (!RegExp(r'[!"#$%&()*+,-./:;<=>?@[\]^_`{|}~]').hasMatch(value)) {
return 'Password must contain at least one special character';
}
return null;
}
@ -182,13 +193,10 @@ class AuthCubit extends Cubit<AuthState> {
debugPrint('token: ${token.accessToken}');
FlutterSecureStorage storage = const FlutterSecureStorage();
await storage.write(
key: Token.loginAccessTokenKey,
value: token.accessToken
);
key: Token.loginAccessTokenKey, value: token.accessToken);
const FlutterSecureStorage().write(
key: UserModel.userUuidKey,
value: Token.decodeToken(token.accessToken)['uuid'].toString()
);
value: Token.decodeToken(token.accessToken)['uuid'].toString());
user = UserModel.fromToken(token);
emailController.clear();
passwordController.clear();
@ -225,20 +233,24 @@ class AuthCubit extends Cubit<AuthState> {
sendOtp() async {
try {
emit(AuthLoading());
await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
await AuthenticationAPI.sendOtp(
body: {'email': email, 'type': 'VERIFICATION'});
emit(AuthSignUpSuccess());
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
}
}
reSendOtp() async {
Future<bool> reSendOtp() async {
try {
emit(AuthLoading());
await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
await AuthenticationAPI.sendOtp(
body: {'email': email, 'type': 'VERIFICATION'});
emit(ResendOtpSuccess());
return true;
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
return false;
}
}
@ -282,13 +294,16 @@ class AuthCubit extends Cubit<AuthState> {
try {
emit(AuthTokenLoading());
const storage = FlutterSecureStorage();
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
StringsManager.firstLaunch) ??
true;
if (firstLaunch) {
storage.deleteAll();
}
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
await SharedPreferencesHelper.saveBoolToSP(
StringsManager.firstLaunch, false);
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
if (value.isEmpty) {
@ -315,7 +330,6 @@ class AuthCubit extends Cubit<AuthState> {
}
}
sendToForgetPassword({required String password}) async {
try {
emit(AuthForgetPassLoading());
@ -325,8 +339,4 @@ class AuthCubit extends Cubit<AuthState> {
emit(AuthForgetPassError(message: 'Something went wrong'));
}
}
}

View File

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

View File

@ -1,5 +1,5 @@
import 'dart:async';
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/acs_bloc/acs_event.dart';
@ -40,6 +40,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
on<ChangeAllSwitch>(_changeAllAcSwitch);
on<IncreaseAllTemp>(_increaseAllTemp);
on<DecreaseAllTemp>(_decreaseAllTemp);
on<AcUpdated>(_onAcUpdated);
}
void _fetchAcsStatus(AcsInitial event, Emitter<AcsState> emit) async {
@ -62,6 +63,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
}
deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
emit(GetAcStatusState(acStatusModel: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
_listenToChanges();
}
} catch (e) {
emit(AcsFailedState(errorMessage: e.toString()));
@ -69,6 +72,29 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$acId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
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 = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
add(AcUpdated());
});
} catch (_) {}
}
_onAcUpdated(AcUpdated event, Emitter<AcsState> emit) {
emit(GetAcStatusState(acStatusModel: deviceStatus));
}
_getAllAcs() async {
deviceStatusList = [];
devicesList = [];
@ -164,7 +190,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
deviceStatus.childLock = lockValue;
emit(AcModifyingState(acStatusModel: deviceStatus));
_runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue);
await _runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue);
}
void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async {

View File

@ -20,6 +20,8 @@ class AcSwitch extends AcsEvent {
List<Object> get props => [acSwitch, deviceId, productId];
}
class AcUpdated extends AcsEvent {}
class AcsInitial extends AcsEvent {
final bool allAcs;
const AcsInitial({required this.allAcs});

View File

@ -1,3 +1,4 @@
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/ceiling_bloc/ceiling_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/ceiling_bloc/ceiling_sensor_state.dart';
@ -15,6 +16,7 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
CeilingSensorBloc({required this.deviceId}) : super(InitialState()) {
on<InitialEvent>(_fetchCeilingSensorStatus);
on<ChangeValueEvent>(_changeValue);
on<CeilingSensorUpdated>(_onCeilingSensorUpdated);
}
void _fetchCeilingSensorStatus(InitialEvent event, Emitter<CeilingSensorState> emit) async {
@ -27,12 +29,36 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
}
deviceStatus = CeilingSensorModel.fromJson(statusModelList);
emit(UpdateState(ceilingSensorModel: deviceStatus));
_listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = CeilingSensorModel.fromJson(statusList);
add(CeilingSensorUpdated());
});
} catch (_) {}
}
_onCeilingSensorUpdated(CeilingSensorUpdated event, Emitter<CeilingSensorState> emit) {
emit(UpdateState(ceilingSensorModel: deviceStatus));
}
void _changeValue(ChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
emit(LoadingNewSate(ceilingSensorModel: deviceStatus));
try {

View File

@ -11,6 +11,8 @@ class LoadingEvent extends CeilingSensorEvent {}
class InitialEvent extends CeilingSensorEvent {}
class CeilingSensorUpdated extends CeilingSensorEvent {}
class ChangeValueEvent extends CeilingSensorEvent {
final int value;
final String code;

View File

@ -1,12 +1,11 @@
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/offline_password_model.dart';
import 'package:syncrow_app/features/devices/model/offline_temporary_password.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
@ -25,6 +24,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
SmartDoorBloc({required this.deviceId}) : super(InitialState()) {
on<InitialEvent>(_fetchSmartDoorStatus);
on<DoorLockUpdated>(_doorLockUpdated);
on<InitialPasswordsPage>(getTemporaryPasswords);
on<InitialOneTimePassword>(getOneTimePasswords);
on<InitialTimeLimitPassword>(getTimeLimitPasswords);
@ -69,23 +69,24 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return passwordController.text;
}
Future generateAndSavePasswordOneTime (GenerateAndSavePasswordOneTimeEvent event, Emitter<SmartDoorState> emit) async {
Future generateAndSavePasswordOneTime(
GenerateAndSavePasswordOneTimeEvent event, Emitter<SmartDoorState> emit) async {
try {
if (isSavingPassword) return;
isSavingPassword = true;
emit(LoadingInitialState());
var res = await DevicesAPI.generateOneTimePassword(deviceId: deviceId);
ApiResponse pass= ApiResponse.fromJson(res);
passwordController.text =pass.data.offlineTempPassword;
passwordId=pass.data.offlineTempPasswordId;
var res = await DevicesAPI.generateOneTimePassword(deviceId: deviceId);
ApiResponse pass = ApiResponse.fromJson(res);
passwordController.text = pass.data.offlineTempPassword;
passwordId = pass.data.offlineTempPasswordId;
Future.delayed(const Duration(seconds: 1), () {
Clipboard.setData(ClipboardData(text: passwordController.text));
Clipboard.setData(ClipboardData(text: passwordController.text));
});
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
emit(FailedState(errorMessage: _.toString()));
}finally {
} finally {
isSavingPassword = false;
}
}
@ -100,20 +101,41 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
deviceStatus = SmartDoorModel.fromJson(statusModelList);
emit(UpdateState(smartDoorModel: deviceStatus));
_listenToChanges();
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = SmartDoorModel.fromJson(statusList);
add(DoorLockUpdated());
});
} catch (_) {}
}
_doorLockUpdated(DoorLockUpdated event, Emitter<SmartDoorState> emit) {
emit(UpdateState(smartDoorModel: deviceStatus));
}
void _renamePassword(RenamePasswordEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.renamePass(
name:passwordNameController.text ,
doorLockUuid:deviceId ,
passwordId:passwordId
);
await DevicesAPI.renamePass(
name: passwordNameController.text, doorLockUuid: deviceId, passwordId: passwordId);
add(InitialOneTimePassword());
add(InitialTimeLimitPassword());
emit(UpdateState(smartDoorModel: deviceStatus));
@ -126,11 +148,14 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
void getTemporaryPasswords(InitialPasswordsPage event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getTemporaryPasswords(deviceId, );
var response = await DevicesAPI.getTemporaryPasswords(
deviceId,
);
if (response is List) {
temporaryPasswords = response.map((item) => TemporaryPassword.fromJson(item)).toList();
} else if (response is Map && response.containsKey('data')) {
temporaryPasswords = (response['data'] as List).map((item) => TemporaryPassword.fromJson(item)).toList();
temporaryPasswords =
(response['data'] as List).map((item) => TemporaryPassword.fromJson(item)).toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
@ -183,25 +208,26 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
bool setStartEndTime(SetStartEndTimeEvent event, Emitter<SmartDoorState> emit) {
emit(LoadingInitialState());
isStartEndTime = event.val;
emit(IsStartEndState(isStartEndTime:isStartEndTime));
emit(IsStartEndState(isStartEndTime: isStartEndTime));
return isStartEndTime;
}
void _updateLock(UpdateLockEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingNewSate(smartDoorModel: deviceStatus));
try {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: deviceId, code: 'normal_open_switch', value: !event.value),
deviceId);
// final response = await DevicesAPI.controlDevice(
// DeviceControlModel(deviceId: deviceId, code: 'normal_open_switch', value: !event.value),
// deviceId);
if (response['success'] ?? false) {
final response = await DevicesAPI.openDoorLock(deviceId);
if (response) {
deviceStatus.normalOpenSwitch = !event.value;
}
} catch (_) {}
emit(UpdateState(smartDoorModel: deviceStatus));
}
Future<void> selectTimeOfLinePassword(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
@ -224,24 +250,28 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
0,
);
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/ 1000; // Divide by 1000 to remove milliseconds
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
} else {
effectiveTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
expirationTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
@ -250,7 +280,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
}
Future<void> selectTimeOnlinePassword(SelectTimeOnlinePasswordEvent event, Emitter<SmartDoorState> emit) async {
Future<void> selectTimeOnlinePassword(
SelectTimeOnlinePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
context: event.context,
@ -288,12 +319,12 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
timePicked.minute,
);
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
@ -305,7 +336,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
expirationTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
@ -322,7 +354,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
try {
isSavingPassword = true;
emit(LoadingSaveState());
var res = await DevicesAPI.createPassword(
await DevicesAPI.createPassword(
deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(),
@ -341,25 +373,25 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Save Successfully');
emit(SaveState());
} catch (_) {
}finally {
} finally {
isSavingPassword = false;
}
}
Future<void> generateAndSavePasswordTimeLimited (GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async {
Future<void> generateAndSavePasswordTimeLimited(
GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async {
if (timeLimitValidate() || isSavingPassword) return;
try {
isSavingPassword = true;
emit(LoadingInitialState());
var res = await DevicesAPI.generateMultiTimePassword(
var res = await DevicesAPI.generateMultiTimePassword(
deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(),
);
ApiResponse pass= ApiResponse.fromJson(res);
passwordController.text =pass.data.offlineTempPassword;
passwordId=pass.data.offlineTempPasswordId;
ApiResponse pass = ApiResponse.fromJson(res);
passwordController.text = pass.data.offlineTempPassword;
passwordId = pass.data.offlineTempPasswordId;
CustomSnackBar.displaySnackBar('Save Successfully');
add(InitialTimeLimitPassword());
Future.delayed(const Duration(seconds: 1), () {
@ -368,8 +400,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
add(InitialPasswordsPage());
}
finally {
} finally {
isSavingPassword = false;
}
}
@ -377,7 +408,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response =
await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId)
.then((value) async {
add(InitialPasswordsPage());
@ -388,7 +418,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
bool _validateInputs() {
if (passwordController.text.length < 7 ) {
if (passwordController.text.length < 7) {
CustomSnackBar.displaySnackBar('Password less than 7');
return true;
}
@ -397,7 +427,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Password required');
return true;
}
if (passwordNameController.text.isEmpty ) {
if (passwordNameController.text.isEmpty) {
CustomSnackBar.displaySnackBar('Password name required');
return true;
}
@ -412,7 +442,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return true;
}
if (repeat == true && (endTime == null || startTime == null || selectedDays == null)) {
if (repeat == true && (endTime == null || startTime == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required ');
return true;
}
@ -420,7 +450,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
bool timeLimitValidate() {
if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select effective time');
return true;
@ -444,7 +473,10 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
List<String> selectedDays = [];
Future<void> toggleDaySelection(ToggleDaySelectionEvent event, Emitter<SmartDoorState> emit,)async {
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<SmartDoorState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
@ -459,8 +491,3 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return DateFormat('HH:mm').format(dateTime);
}
}

View File

@ -9,10 +9,15 @@ abstract class SmartDoorEvent extends Equatable {
}
class InitialEvent extends SmartDoorEvent {}
class InitialPasswordsPage extends SmartDoorEvent {}
class InitialOneTimePassword extends SmartDoorEvent {}
class InitialTimeLimitPassword extends SmartDoorEvent {}
class DoorLockUpdated extends SmartDoorEvent {}
class UpdateLockEvent extends SmartDoorEvent {
final bool value;
const UpdateLockEvent({required this.value});
@ -26,6 +31,7 @@ class SavePasswordEvent extends SmartDoorEvent {
@override
List<Object> get props => [context];
}
class GenerateAndSavePasswordTimeLimitEvent extends SmartDoorEvent {
final BuildContext context;
const GenerateAndSavePasswordTimeLimitEvent({required this.context});
@ -40,28 +46,26 @@ class GenerateAndSavePasswordOneTimeEvent extends SmartDoorEvent {
List<Object> get props => [context];
}
class GeneratePasswordEvent extends SmartDoorEvent {
}
class GeneratePasswordEvent extends SmartDoorEvent {}
class SelectTimeEvent extends SmartDoorEvent {
final BuildContext context;
final BuildContext context;
final bool isEffective;
const SelectTimeEvent({required this.context,required this.isEffective});
const SelectTimeEvent({required this.context, required this.isEffective});
@override
List<Object> get props => [context,isEffective];
List<Object> get props => [context, isEffective];
}
class SelectTimeOnlinePasswordEvent extends SmartDoorEvent {
final BuildContext context;
final BuildContext context;
final bool isEffective;
const SelectTimeOnlinePasswordEvent({required this.context,required this.isEffective});
const SelectTimeOnlinePasswordEvent({required this.context, required this.isEffective});
@override
List<Object> get props => [context,isEffective];
List<Object> get props => [context, isEffective];
}
class ToggleRepeatEvent extends SmartDoorEvent {}
class SetStartEndTimeEvent extends SmartDoorEvent {
final bool val;
const SetStartEndTimeEvent({required this.val});
@ -70,7 +74,7 @@ class SetStartEndTimeEvent extends SmartDoorEvent {
}
class DeletePasswordEvent extends SmartDoorEvent {
final String passwordId;
final String passwordId;
const DeletePasswordEvent({required this.passwordId});
@override
@ -78,7 +82,7 @@ class DeletePasswordEvent extends SmartDoorEvent {
}
class ToggleDaySelectionEvent extends SmartDoorEvent {
final String key;
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
@ -89,12 +93,9 @@ class ChangeTimeEvent extends SmartDoorEvent {
final dynamic val;
final bool isStartEndTime;
const ChangeTimeEvent({required this.val,required this.isStartEndTime});
const ChangeTimeEvent({required this.val, required this.isStartEndTime});
@override
List<Object> get props => [val,isStartEndTime];
List<Object> get props => [val, isStartEndTime];
}
class RenamePasswordEvent extends SmartDoorEvent {
}
class RenamePasswordEvent extends SmartDoorEvent {}

View File

@ -1,4 +1,5 @@
import 'dart:async';
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/three_gang_bloc/three_gang_event.dart';
@ -20,6 +21,10 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
secondCountDown: 0,
thirdCountDown: 0);
Timer? _timer;
// Timer? _firstSwitchTimer;
// Timer? _secondSwitchTimer;
// Timer? _thirdSwitchTimer;
bool threeGangGroup = false;
List<DeviceModel> devicesList = [];
List<GroupThreeGangModel> groupThreeGangList = [];
@ -27,6 +32,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
ThreeGangBloc({required this.threeGangId}) : super(InitialState()) {
on<InitialEvent>(_fetchThreeGangStatus);
on<ThreeGangUpdated>(_threeGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSecondSwitchStatusEvent>(_changeSecondSwitch);
on<ChangeThirdSwitchStatusEvent>(_changeThirdSwitch);
@ -85,6 +91,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
}
deviceStatus = ThreeGangModel.fromJson(statusModelList);
emit(UpdateState(threeGangModel: deviceStatus));
_listenToChanges();
}
} catch (e) {
emit(FailedState(error: e.toString()));
@ -92,6 +99,34 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$threeGangId');
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 = ThreeGangModel.fromJson(statusList);
if (!isClosed) {
add(ThreeGangUpdated());
}
});
} catch (_) {}
}
_threeGangUpdated(ThreeGangUpdated event, Emitter<ThreeGangState> emit) {
emit(UpdateState(threeGangModel: deviceStatus));
}
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<ThreeGangState> emit) async {
emit(LoadingNewSate(threeGangModel: deviceStatus));
try {
@ -111,16 +146,22 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
emit(UpdateState(threeGangModel: deviceStatus));
}
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
code: 'switch_1',
value: !event.value),
threeGangGroup ? event.deviceId : threeGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeGangGroup));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
code: 'switch_1',
value: !event.value),
threeGangGroup ? event.deviceId : threeGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeGangGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeGangGroup));
}
@ -146,16 +187,22 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
emit(UpdateState(threeGangModel: deviceStatus));
}
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
code: 'switch_2',
value: !event.value),
threeGangGroup ? event.deviceId : threeGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeGangGroup));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
code: 'switch_2',
value: !event.value),
threeGangGroup ? event.deviceId : threeGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeGangGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeGangGroup));
}
@ -180,16 +227,22 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
emit(UpdateState(threeGangModel: deviceStatus));
}
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
code: 'switch_3',
value: !event.value),
threeGangGroup ? event.deviceId : threeGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeGangGroup));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeGangGroup ? event.deviceId : threeGangId,
code: 'switch_3',
value: !event.value),
threeGangGroup ? event.deviceId : threeGangId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeGangGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeGangGroup));
}
@ -407,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) {

View File

@ -9,6 +9,8 @@ abstract class ThreeGangEvent extends Equatable {
class LoadingEvent extends ThreeGangEvent {}
class ThreeGangUpdated extends ThreeGangEvent {}
class InitialEvent extends ThreeGangEvent {
final bool groupScreen;
const InitialEvent({required this.groupScreen});

View File

@ -1,3 +1,4 @@
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_state.dart';
import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_event.dart';
@ -16,6 +17,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
on<InitialEvent>(_fetchCeilingSensorStatus);
on<ChangeIndicatorEvent>(_changeIndicator);
on<ChangeValueEvent>(_changeValue);
on<WallSensorUpdatedEvent>(_wallSensorUpdated);
}
void _fetchCeilingSensorStatus(InitialEvent event, Emitter<WallSensorState> emit) async {
@ -28,12 +30,36 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
}
deviceStatus = WallSensorModel.fromJson(statusModelList);
emit(UpdateState(wallSensorModel: deviceStatus));
_listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) {
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = WallSensorModel.fromJson(statusList);
add(WallSensorUpdatedEvent());
});
} catch (_) {}
}
_wallSensorUpdated(WallSensorUpdatedEvent event, Emitter<WallSensorState> emit) {
emit(UpdateState(wallSensorModel: deviceStatus));
}
void _changeIndicator(ChangeIndicatorEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingNewSate(wallSensorModel: deviceStatus));
try {

View File

@ -11,6 +11,8 @@ class LoadingEvent extends WallSensorEvent {}
class InitialEvent extends WallSensorEvent {}
class WallSensorUpdatedEvent extends WallSensorEvent {}
class ChangeIndicatorEvent extends WallSensorEvent {
final bool value;
const ChangeIndicatorEvent({required this.value});

View File

@ -4,28 +4,47 @@ class CeilingSensorModel {
String presenceState;
int sensitivity;
String checkingResult;
int presenceRange;
int sportsPara;
String bodyMovement;
CeilingSensorModel({
required this.presenceState,
required this.sensitivity,
required this.checkingResult,
});
CeilingSensorModel(
{required this.presenceState,
required this.sensitivity,
required this.checkingResult,
required this.presenceRange,
required this.sportsPara,
required this.bodyMovement});
factory CeilingSensorModel.fromJson(List<StatusModel> jsonList) {
late String _presenceState;
late int _sensitivity;
late String _checkingResult;
int _presenceRange = 1;
int _sportsPara = 1;
String _bodyMovement = 'none';
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'presence_state') {
_presenceState = jsonList[i].value ?? 'none';
} else if (jsonList[i].code == 'sensitivity') {
_sensitivity = jsonList[i].value ?? false;
_sensitivity = jsonList[i].value ?? 1;
} else if (jsonList[i].code == 'checking_result') {
_checkingResult = jsonList[i].value ?? false;
_checkingResult = jsonList[i].value ?? '';
} else if (jsonList[i].code == 'presence_range') {
_presenceRange = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'sports_para') {
_sportsPara = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'body_movement') {
_bodyMovement = jsonList[i].value ?? '';
}
}
return CeilingSensorModel(
presenceState: _presenceState, sensitivity: _sensitivity, checkingResult: _checkingResult);
presenceState: _presenceState,
sensitivity: _sensitivity,
checkingResult: _checkingResult,
presenceRange: _presenceRange,
sportsPara: _sportsPara,
bodyMovement: _bodyMovement);
}
}

View File

@ -35,9 +35,9 @@ class WallSensorModel {
if (jsonList[i].code == 'presence_state') {
_presenceState = jsonList[i].value ?? 'none';
} else if (jsonList[i].code == 'far_detection') {
_farDetection = jsonList[i].value ?? false;
_farDetection = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'presence_time') {
_presenceTime = jsonList[i].value ?? false;
_presenceTime = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'motion_sensitivity_value') {
_motionSensitivity = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'motionless_sensitivity') {
@ -47,7 +47,7 @@ class WallSensorModel {
} else if (jsonList[i].code == 'illuminance_value') {
_illuminance = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'indicator') {
_indicator = jsonList[i].value ?? 0;
_indicator = jsonList[i].value ?? false;
}
}
return WallSensorModel(

View File

@ -34,8 +34,13 @@ class CeilingSensorInterface extends StatelessWidget {
create: (context) =>
CeilingSensorBloc(deviceId: ceilingSensor.uuid ?? '')..add(InitialEvent()),
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(builder: (context, state) {
CeilingSensorModel ceilingSensorModel =
CeilingSensorModel(presenceState: 'none', sensitivity: 1, checkingResult: '');
CeilingSensorModel ceilingSensorModel = CeilingSensorModel(
presenceState: 'none',
sensitivity: 1,
checkingResult: '',
presenceRange: 1,
sportsPara: 1,
bodyMovement: 'none');
if (state is UpdateState) {
ceilingSensorModel = state.ceilingSensorModel;
} else if (state is LoadingNewSate) {
@ -178,7 +183,8 @@ class CeilingSensorInterface extends StatelessWidget {
children: [
const BodySmall(text: 'Sports Para'),
BodyLarge(
text: '0',
text: ceilingSensorModel.sportsPara
.toString(),
style: context.bodyLarge.copyWith(
fontWeight: FontsManager.bold,
),
@ -204,7 +210,8 @@ class CeilingSensorInterface extends StatelessWidget {
textOverflow: TextOverflow.ellipsis,
),
BodyLarge(
text: '0.0M',
text:
'${ceilingSensorModel.presenceRange}M',
textOverflow: TextOverflow.ellipsis,
style: context.bodyLarge.copyWith(
fontWeight: FontsManager.bold,
@ -231,7 +238,7 @@ class CeilingSensorInterface extends StatelessWidget {
textOverflow: TextOverflow.ellipsis,
),
BodyLarge(
text: 'none',
text: ceilingSensorModel.bodyMovement,
textOverflow: TextOverflow.ellipsis,
style: context.bodyLarge.copyWith(
fontWeight: FontsManager.bold,

View File

@ -1,14 +1,10 @@
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/acs_bloc/acs_event.dart';
// import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.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/smart_door_model.dart';
// import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_status_bar.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';
@ -37,34 +33,41 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
value: smartDoorModel.unlockRequest > 0 ? 1 : 0,
duration: Duration(seconds: smartDoorModel.unlockRequest),
);
_animation = Tween<double>(begin: 0, end: 1.0).animate(_animationController)
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 ?? "");
// }
}
// 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(() {});
});
}
@ -88,14 +91,18 @@ class _DoorLockButtonState extends State<DoorLockButton> with SingleTickerProvid
WidgetStateProperty.all(ColorsManager.primaryColorWithOpacity.withOpacity(0.1)),
borderRadius: BorderRadius.circular(999),
onTapDown: (details) {
if (_animationController.status == AnimationStatus.dismissed) {
_animationController.forward();
} else if (_animationController.status == AnimationStatus.completed) {
_animationController.reverse();
} else if (_animationController.status == AnimationStatus.forward) {
_animationController.reverse();
} else if (_animationController.status == AnimationStatus.reverse) {
_animationController.forward();
// if (_animationController.status == AnimationStatus.dismissed) {
// _animationController.forward();
// } else if (_animationController.status == AnimationStatus.completed) {
// _animationController.reverse();
// } else if (_animationController.status == AnimationStatus.forward) {
// _animationController.reverse();
// } else if (_animationController.status == AnimationStatus.reverse) {
// _animationController.forward();
// }
if (smartDoorModel.unlockRequest > 0) {
BlocProvider.of<SmartDoorBloc>(context)
.add(UpdateLockEvent(value: smartDoorModel.normalOpenSwitch));
}
},
onTapUp: (details) {

View File

@ -7,27 +7,22 @@ import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_sta
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/popup_menu_widget.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_button.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_grid.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_status_bar.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 DoorInterface extends StatelessWidget {
DoorInterface({super.key, required this.doorLock});
const DoorInterface({super.key, required this.doorLock});
final DeviceModel doorLock;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SmartDoorBloc(deviceId: doorLock.uuid ?? '')..add(InitialEvent()),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@ -63,32 +58,32 @@ class DoorInterface extends StatelessWidget {
}
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: DeviceAppbar(
deviceName: doorLock.name!,
deviceUuid: doorLock.uuid!,
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
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: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: DeviceAppbar(
deviceName: doorLock.name!,
deviceUuid: doorLock.uuid!,
),
child: SafeArea(
child: Padding(
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(
top: Constants.appBarHeight,
left: Constants.defaultPadding,
@ -98,38 +93,35 @@ class DoorInterface extends StatelessWidget {
? const Center(
child: RefreshProgressIndicator(),
)
:
RefreshIndicator(
onRefresh: () async {
BlocProvider.of<SmartDoorBloc>(context).add(InitialEvent());
},
child:
ListView(
children: [
DoorLockStatusBar(
smartDoorModel: smartDoorModel,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DoorLockButton(
doorLock: doorLock,
smartDoorModel: smartDoorModel,
),
DoorLockGrid( uuid: doorLock.uuid!, ),
],
)
],
)),
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<SmartDoorBloc>(context).add(InitialEvent());
},
child: ListView(
children: [
DoorLockStatusBar(
smartDoorModel: smartDoorModel,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DoorLockButton(
doorLock: doorLock,
smartDoorModel: smartDoorModel,
),
DoorLockGrid(
uuid: doorLock.uuid!,
),
],
)
],
)),
),
),
),
),
),
));
));
}),
);
}
}

View File

@ -18,7 +18,7 @@ class ManageHomeView extends StatelessWidget {
title: 'Manage Your Home',
child: spaces == null
? const Center(
child: CircularProgressIndicator(),
child: BodyMedium(text: 'No spaces found'),
)
: Column(
children: [
@ -30,8 +30,7 @@ class ManageHomeView extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children:
List.generate(
children: List.generate(
spaces.length,
(index) {
if (index == spaces.length - 1) {
@ -43,12 +42,10 @@ class ManageHomeView extends StatelessWidget {
)));
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(
text: StringHelpers.toTitleCase(
spaces[index].name ?? "")),
text: StringHelpers.toTitleCase(spaces[index].name ?? "")),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
@ -76,14 +73,10 @@ class ManageHomeView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(
text: HomeCubit.getInstance()
.spaces![index]
.name ??
""),
text: HomeCubit.getInstance().spaces![index].name ?? ""),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
@ -92,8 +85,7 @@ class ManageHomeView extends StatelessWidget {
],
),
Container(
margin:
const EdgeInsets.symmetric(vertical: 15),
margin: const EdgeInsets.symmetric(vertical: 15),
height: 1,
color: ColorsManager.greyColor,
),

View File

@ -0,0 +1,45 @@
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,6 +733,10 @@ 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";
@ -1029,4 +1033,5 @@ class Assets {
static const String assetsPresenceState =
"assets/icons/functions_icons/automation_functions/presence_state.svg";
}

View File

@ -81,8 +81,7 @@ abstract class ApiEndpoints {
static const String controlGroup = '/group/control';
//GET
static const String groupBySpace = '/group/{unitUuid}';
static const String devicesByGroupName =
'/group/{unitUuid}/devices/{groupName}';
static const String devicesByGroupName = '/group/{unitUuid}/devices/{groupName}';
static const String groupByUuid = '/group/{groupUuid}';
//DELETE
@ -94,18 +93,17 @@ abstract class ApiEndpoints {
static const String addDeviceToRoom = '/device/room';
static const String addDeviceToGroup = '/device/group';
static const String controlDevice = '/device/{deviceUuid}/control';
static const String firmwareDevice =
'/device/{deviceUuid}/firmware/{firmwareVersion}';
static const String firmwareDevice = '/device/{deviceUuid}/firmware/{firmwareVersion}';
static const String getDevicesByUserId = '/device/user/{userId}';
static const String getDevicesByUnitId = '/device/unit/{unitUuid}';
static const String openDoorLock = '/door-lock/open/{doorLockUuid}';
//GET
static const String deviceByRoom = '/device/room';
static const String deviceByUuid = '/device/{deviceUuid}';
static const String deviceFunctions = '/device/{deviceUuid}/functions';
static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices';
static const String deviceFunctionsStatus =
'/device/{deviceUuid}/functions/status';
static const String deviceFunctionsStatus = '/device/{deviceUuid}/functions/status';
///Device Permission Module
//POST
@ -130,29 +128,24 @@ abstract class ApiEndpoints {
static const String getUnitAutomation = '/automation/{unitUuid}';
static const String getAutomationDetails =
'/automation/details/{automationId}';
static const String getAutomationDetails = '/automation/details/{automationId}';
/// PUT
static const String updateScene = '/scene/tap-to-run/{sceneId}';
static const String updateAutomation = '/automation/{automationId}';
static const String updateAutomationStatus =
'/automation/status/{automationId}';
static const String updateAutomationStatus = '/automation/status/{automationId}';
/// DELETE
static const String deleteScene = '/scene/tap-to-run/{unitUuid}/{sceneId}';
static const String deleteAutomation =
'/automation/{unitUuid}/{automationId}';
static const String deleteAutomation = '/automation/{unitUuid}/{automationId}';
//////////////////////Door Lock //////////////////////
//online
static const String addTemporaryPassword =
'/door-lock/temporary-password/online/{doorLockUuid}';
static const String getTemporaryPassword =
'/door-lock/temporary-password/online/{doorLockUuid}';
static const String addTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}';
static const String getTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}';
//one-time offline
static const String addOneTimeTemporaryPassword =
@ -160,8 +153,6 @@ abstract class ApiEndpoints {
static const String getOneTimeTemporaryPassword =
'/door-lock/temporary-password/offline/one-time/{doorLockUuid}';
//user
static const String getUser = '/user/{userUuid}';

View File

@ -46,6 +46,17 @@ class DevicesAPI {
}
}
static Future<bool> openDoorLock(String deviceId) async {
final response = await _httpService.post(
path: ApiEndpoints.openDoorLock.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json['success'] ?? false;
},
);
return response;
}
static Future<List<DevicesCategoryModel>> fetchGroups(String spaceId) async {
// Map<String, dynamic> params = {"homeId": spaceId, "pageSize": 100, "pageNo": 1};
@ -69,17 +80,13 @@ class DevicesAPI {
return response;
}
static Future<Map<String, dynamic>> renamePass({
required String name,
required String doorLockUuid,
required String passwordId}) async {
static Future<Map<String, dynamic>> renamePass(
{required String name, required String doorLockUuid, required String passwordId}) async {
final response = await _httpService.put(
path: ApiEndpoints.renamePassword
.replaceAll('{doorLockUuid}', doorLockUuid)
.replaceAll('{passwordId}', passwordId),
body: {
"name": name
},
body: {"name": name},
expectedResponseModel: (json) {
return json;
},
@ -156,9 +163,11 @@ class DevicesAPI {
return response;
}
static Future getTemporaryPasswords(String deviceId, ) async {
static Future getTemporaryPasswords(
String deviceId,
) async {
final response = await _httpService.get(
path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
@ -196,7 +205,8 @@ class DevicesAPI {
required String effectiveTime,
required String invalidTime,
required String deviceId,
List<Schedule>? scheduleList,}) async {
List<Schedule>? scheduleList,
}) async {
Map<String, dynamic> body = {
"name": name,
"password": password,
@ -216,7 +226,7 @@ class DevicesAPI {
return response;
}
static Future generateOneTimePassword({deviceId}) async {
static Future generateOneTimePassword({deviceId}) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
@ -231,15 +241,12 @@ class DevicesAPI {
}
}
static Future generateMultiTimePassword({deviceId,effectiveTime,invalidTime}) async {
static Future generateMultiTimePassword({deviceId, effectiveTime, invalidTime}) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: true,
body: {
"effectiveTime": effectiveTime,
"invalidTime": invalidTime
},
body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime},
expectedResponseModel: (json) {
return json;
},
@ -263,5 +270,4 @@ class DevicesAPI {
);
return response;
}
}

View File

@ -5,10 +5,10 @@ packages:
dependency: transitive
description:
name: _flutterfire_internals
sha256: fe4c077084ddda88f327dc1c96d16631cd68d4948644593fcbcd911c2c89e2fa
sha256: "37a42d06068e2fe3deddb2da079a8c4d105f241225ba27b7122b37e9865fd8f7"
url: "https://pub.dev"
source: hosted
version: "1.3.23"
version: "1.3.35"
args:
dependency: transitive
description:
@ -245,10 +245,10 @@ packages:
dependency: "direct main"
description:
name: firebase_core
sha256: "797379ea206eaeeb62499775de812761493d0692890fdc7f90b6183a3369176d"
sha256: "26de145bb9688a90962faec6f838247377b0b0d32cc0abecd9a4e43525fc856c"
url: "https://pub.dev"
source: hosted
version: "2.25.5"
version: "2.32.0"
firebase_core_platform_interface:
dependency: transitive
description:
@ -281,6 +281,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.6.23"
firebase_database:
dependency: "direct main"
description:
name: firebase_database
sha256: "3b9ca306d26ad243ccbc4c717ff6e8563a080ebe11ee77fa7349b419c894b42d"
url: "https://pub.dev"
source: hosted
version: "10.5.7"
firebase_database_platform_interface:
dependency: transitive
description:
name: firebase_database_platform_interface
sha256: "5864cc362275465e9bd682b243f19419c9d78b861c2db820241eea596ae3b320"
url: "https://pub.dev"
source: hosted
version: "0.2.5+35"
firebase_database_web:
dependency: transitive
description:
name: firebase_database_web
sha256: a6008395dd20e8b8dde0691b441c181a1216c3866f89f48dcb6889d34fd35905
url: "https://pub.dev"
source: hosted
version: "0.2.5+7"
fixnum:
dependency: transitive
description:

View File

@ -5,7 +5,7 @@ description: This is the mobile application project, developed with Flutter for
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: "none" # Remove this line if you wish to publish to pub.dev
version: 1.0.2+19
version: 1.0.3+21
environment:
sdk: ">=3.0.6 <4.0.0"
@ -45,6 +45,7 @@ dependencies:
time_picker_spinner: ^1.0.0
image_picker: ^1.1.2
device_info_plus: ^10.1.0
firebase_database: ^10.5.7
dev_dependencies:
flutter_lints: ^3.0.1