Compare commits

..

25 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
f6fbf452a0 Merge pull request #45 from SyncrowIOT/fix_bugs_doorlock_qa
fix password
2024-08-07 17:25:48 +03:00
5aec3d37fb fix password 2024-08-07 17:20:19 +03:00
a32d885e50 Changed the action executor of the tab to run scenes and changed the order of the effective days 2024-08-07 15:52:27 +03:00
afe37dd68a Merge pull request #44 from SyncrowIOT/automation_fixes3
Automation fixes3
2024-08-06 15:28:38 +03:00
f83224ce60 Merge pull request #43 from SyncrowIOT/update_door_lock
door lock password update
2024-08-06 15:07:12 +03:00
0ef2f3b866 door lock password update 2024-08-06 14:58:06 +03:00
85 changed files with 2699 additions and 952 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,15 +1,18 @@
import 'dart:math';
import 'package:day_picker/model/day_in_week.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';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/create_temporary_password_model.dart';
import 'package:syncrow_app/features/devices/model/temporary_password_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/hour_picker_dialog.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -17,21 +20,77 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
final String deviceId;
late SmartDoorModel deviceStatus;
static String pageType = '';
bool isSavingPassword = false;
SmartDoorBloc({required this.deviceId}) : super(InitialState()) {
on<InitialEvent>(_fetchSmartDoorStatus);
on<DoorLockUpdated>(_doorLockUpdated);
on<InitialPasswordsPage>(getTemporaryPasswords);
on<InitialOneTimePassword>(getOneTimePasswords);
on<InitialTimeLimitPassword>(getTimeLimitPasswords);
on<UpdateLockEvent>(_updateLock);
on<SavePasswordEvent>(savePassword);
on<ToggleRepeatEvent>(toggleRepeat);
on<SetStartEndTimeEvent>(setStartEndTime);
on<ChangeTimeEvent>(changeTime);
on<GeneratePasswordEvent>(generate7DigitNumber);
on<SelectTimeEvent>(selectTime);
on<SelectTimeEvent>(selectTimeOfLinePassword);
on<SelectTimeOnlinePasswordEvent>(selectTimeOnlinePassword);
on<DeletePasswordEvent>(deletePassword);
on<GenerateAndSavePasswordTimeLimitEvent>(generateAndSavePasswordTimeLimited);
on<GenerateAndSavePasswordOneTimeEvent>(generateAndSavePasswordOneTime);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<RenamePasswordEvent>(_renamePassword);
}
TextEditingController passwordController = TextEditingController();
TextEditingController passwordNameController = TextEditingController();
String effectiveTime = 'Select Time';
String passwordId = '';
int? effectiveTimeTimeStamp;
String expirationTime = 'Select Time';
int? expirationTimeTimeStamp;
bool repeat = false;
bool isStartEndTime = true;
DateTime? startTime;
DateTime? endTime;
List<TemporaryPassword>? temporaryPasswords = [];
List<OfflinePasswordModel>? oneTimePasswords = [];
List<OfflinePasswordModel>? timeLimitPasswords = [];
Future generate7DigitNumber(GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingInitialState());
passwordController.clear();
Random random = Random();
int min = 1000000;
int max = 9999999;
passwordController.text = (min + random.nextInt(max - min + 1)).toString();
emit(GeneratePasswordState());
return passwordController.text;
}
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;
Future.delayed(const Duration(seconds: 1), () {
Clipboard.setData(ClipboardData(text: passwordController.text));
});
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
emit(FailedState(errorMessage: _.toString()));
} finally {
isSavingPassword = false;
}
}
void _fetchSmartDoorStatus(InitialEvent event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
@ -42,6 +101,44 @@ 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());
await DevicesAPI.renamePass(
name: passwordNameController.text, doorLockUuid: deviceId, passwordId: passwordId);
add(InitialOneTimePassword());
add(InitialTimeLimitPassword());
emit(UpdateState(smartDoorModel: deviceStatus));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
return;
@ -51,15 +148,14 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
void getTemporaryPasswords(InitialPasswordsPage event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
pageType = event.type!;
var response = await DevicesAPI.getTemporaryPasswords(deviceId, pageType);
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();
} else {
throw Exception("Unexpected response format");
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
@ -67,69 +163,125 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
}
}
TextEditingController passwordController = TextEditingController();
TextEditingController passwordNameController = TextEditingController();
String effectiveTime = 'Select Time';
int? effectiveTimeTimeStamp;
String expirationTime = 'Select Time';
int? expirationTimeTimeStamp;
bool repeat = false;
bool isStartEndTime = true;
List<String>? selectedDay;
DateTime? startTime;
DateTime? endTime;
List<TemporaryPassword>? temporaryPasswords = [];
List<TemporaryPassword>? oneTimePasswords = [];
void getOneTimePasswords(InitialOneTimePassword event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getOneTimePasswords(deviceId);
if (response is List) {
oneTimePasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
}
}
void getTimeLimitPasswords(InitialTimeLimitPassword event, Emitter<SmartDoorState> emit) async {
try {
emit(LoadingInitialState());
var response = await DevicesAPI.getTimeLimitPasswords(deviceId);
if (response is List) {
timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList();
}
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!));
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
}
}
changeTime(ChangeTimeEvent event, Emitter<SmartDoorState> emit) {
emit(LoadingInitialState());
if (event.isStartEndTime == true) {
startTime = event.val;
} else {
endTime = event.val;
}
emit(ChangeTimeState());
}
bool toggleRepeat(ToggleRepeatEvent event, Emitter<SmartDoorState> emit) {
emit(LoadingInitialState());
repeat = !repeat;
emit(IsRepeatState());
emit(IsRepeatState(repeat: repeat));
return repeat;
}
bool setStartEndTime(SetStartEndTimeEvent event, Emitter<SmartDoorState> emit) {
emit(LoadingInitialState());
isStartEndTime = event.val;
emit(IsStartEndState());
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));
}
void generate7DigitNumber(GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingInitialState());
passwordController.clear();
Random random = Random();
int min = 1000000;
int max = 9999999;
passwordController.text = (min + random.nextInt(max - min + 1)).toString();
emit(GeneratePasswordState());
Future<void> selectTimeOfLinePassword(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
context: event.context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2101),
);
if (picked != null) {
final TimeOfDay? timePicked = await showHourPicker(
context: event.context,
initialTime: TimeOfDay.now(),
);
if (timePicked != null) {
final selectedDateTime = DateTime(
picked.year,
picked.month,
picked.day,
timePicked.hour,
0,
);
final selectedTimestamp = DateTime(
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
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
expirationTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
emit(TimeSelectedState());
}
}
}
Future<void> selectTime(SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
Future<void> selectTimeOnlinePassword(
SelectTimeOnlinePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState());
final DateTime? picked = await showDatePicker(
context: event.context,
@ -166,7 +318,6 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
timePicked.hour,
timePicked.minute,
);
// Convert selectedDateTime to a timestamp without seconds and milliseconds
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
@ -185,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
@ -202,8 +354,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
try {
isSavingPassword = true;
emit(LoadingSaveState());
var res = await DevicesAPI.createPassword(
pageType: pageType,
await DevicesAPI.createPassword(
deviceId: deviceId,
effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString(),
@ -214,24 +365,52 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
Schedule(
effectiveTime: getTimeOnly(startTime),
invalidTime: getTimeOnly(endTime).toString(),
workingDay: selectedDay!,
workingDay: selectedDays,
),
],
);
Navigator.of(event.context).pop(true);
CustomSnackBar.displaySnackBar('Save Successfully');
emit(SaveState());
} catch (_) {}finally {
} catch (_) {
} finally {
isSavingPassword = false;
}
}
Future<void> generateAndSavePasswordTimeLimited(
GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async {
if (timeLimitValidate() || isSavingPassword) return;
try {
isSavingPassword = true;
emit(LoadingInitialState());
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;
CustomSnackBar.displaySnackBar('Save Successfully');
add(InitialTimeLimitPassword());
Future.delayed(const Duration(seconds: 1), () {
Clipboard.setData(ClipboardData(text: passwordController.text));
});
emit(const GeneratePasswordOneTimestate(generated: true));
} catch (_) {
add(InitialPasswordsPage());
} finally {
isSavingPassword = false;
}
}
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(type: pageType));
await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId)
.then((value) async {
add(InitialPasswordsPage());
});
} catch (e) {
emit(FailedState(errorMessage: e.toString()));
@ -243,6 +422,7 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Password less than 7');
return true;
}
if (passwordController.text.isEmpty) {
CustomSnackBar.displaySnackBar('Password required');
return true;
@ -251,6 +431,25 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Password name required');
return true;
}
if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select effective time');
return true;
}
if (expirationTime == 'Select Time' || expirationTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select expiration time');
return true;
}
if (repeat == true && (endTime == null || startTime == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required ');
return true;
}
return false;
}
bool timeLimitValidate() {
if (effectiveTime == 'Select Time' || effectiveTimeTimeStamp == null) {
CustomSnackBar.displaySnackBar('Select effective time');
return true;
@ -259,23 +458,34 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
CustomSnackBar.displaySnackBar('Select expiration time');
return true;
}
if (repeat == true && (endTime == null || startTime == null || selectedDay == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required ');
return true;
}
return false;
}
List<DayInWeek> days = [
DayInWeek("S", dayKey: 'Sun'),
DayInWeek("M", dayKey: 'Mon'),
DayInWeek("T", dayKey: 'Tue'),
DayInWeek("W", dayKey: 'Wed'),
DayInWeek("T", dayKey: 'Thu'),
DayInWeek("F", dayKey: 'Fri'),
DayInWeek("S", dayKey: 'Sat'),
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"},
];
List<String> selectedDays = [];
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<SmartDoorState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
}
String getTimeOnly(DateTime? dateTime) {
if (dateTime == null) return '';
return DateFormat('HH:mm').format(dateTime);

View File

@ -9,12 +9,15 @@ abstract class SmartDoorEvent extends Equatable {
}
class InitialEvent extends SmartDoorEvent {}
class InitialPasswordsPage extends SmartDoorEvent {
final String? type;
const InitialPasswordsPage({ this.type});
}
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});
@ -29,39 +32,70 @@ class SavePasswordEvent extends SmartDoorEvent {
List<Object> get props => [context];
}
class GeneratePasswordEvent extends SmartDoorEvent {}
class SelectTimeEvent extends SmartDoorEvent {
final BuildContext context;
final bool isEffective;
const SelectTimeEvent({required this.context,required this.isEffective});
class GenerateAndSavePasswordTimeLimitEvent extends SmartDoorEvent {
final BuildContext context;
const GenerateAndSavePasswordTimeLimitEvent({required this.context});
@override
List<Object> get props => [context,isEffective];
List<Object> get props => [context];
}
class GenerateAndSavePasswordOneTimeEvent extends SmartDoorEvent {
final BuildContext context;
const GenerateAndSavePasswordOneTimeEvent({required this.context});
@override
List<Object> get props => [context];
}
class GeneratePasswordEvent extends SmartDoorEvent {}
class SelectTimeEvent extends SmartDoorEvent {
final BuildContext context;
final bool isEffective;
const SelectTimeEvent({required this.context, required this.isEffective});
@override
List<Object> get props => [context, isEffective];
}
class SelectTimeOnlinePasswordEvent extends SmartDoorEvent {
final BuildContext context;
final bool isEffective;
const SelectTimeOnlinePasswordEvent({required this.context, required this.isEffective});
@override
List<Object> get props => [context, isEffective];
}
class ToggleRepeatEvent extends SmartDoorEvent {}
class SetStartEndTimeEvent extends SmartDoorEvent {
final bool val;
const SetStartEndTimeEvent({required this.val});
@override
List<Object> get props => [val];
}
class DeletePasswordEvent extends SmartDoorEvent {
final String passwordId;
final String passwordId;
const DeletePasswordEvent({required this.passwordId});
@override
List<Object> get props => [passwordId];
}
class ToggleDaySelectionEvent extends SmartDoorEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
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 {}

View File

@ -38,13 +38,27 @@ class FailedState extends SmartDoorState {
List<Object> get props => [errorMessage];
}
class GeneratePasswordState extends SmartDoorState {}
class GeneratePasswordState extends SmartDoorState {
}
class TimeSelectedState extends SmartDoorState {}
class IsRepeatState extends SmartDoorState {}
class IsRepeatState extends SmartDoorState {
final bool repeat;
const IsRepeatState({required this.repeat});
class IsStartEndState extends SmartDoorState {}
@override
List<Object> get props => [repeat];
}
class IsStartEndState extends SmartDoorState {
final bool isStartEndTime;
const IsStartEndState({required this.isStartEndTime});
@override
List<Object> get props => [isStartEndTime];
}
class ChangeStartTimeState extends SmartDoorState {}
@ -56,6 +70,12 @@ class SaveState extends SmartDoorState {}
class LoadingSaveState extends SmartDoorState {}
class GeneratePasswordOneTimestate extends SmartDoorState {
final bool generated;
const GeneratePasswordOneTimestate({required this.generated});
List<Object> get props => [generated];
}
class TemporaryPasswordsLoadedState extends SmartDoorState {
final List<TemporaryPassword> temporaryPassword;
const TemporaryPasswordsLoadedState({required this.temporaryPassword});

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

@ -0,0 +1,63 @@
class OfflinePasswordModel {
final dynamic gmtCreate;
final dynamic gmtExpired;
final dynamic gmtStart;
final bool hasClearPwd;
final String optUid;
final String pwd;
final dynamic pwdId;
final String pwdName;
final String pwdTypeCode;
final String revokedPwdName;
final dynamic status;
OfflinePasswordModel({
required this.gmtCreate,
required this.gmtExpired,
required this.gmtStart,
required this.hasClearPwd,
required this.optUid,
required this.pwd,
required this.pwdId,
required this.pwdName,
required this.pwdTypeCode,
required this.revokedPwdName,
required this.status,
});
// Factory method to create a Password from a JSON map
factory OfflinePasswordModel.fromJson(Map<String, dynamic> json) {
return OfflinePasswordModel(
gmtCreate: json['gmtCreate'],
gmtExpired: json['gmtExpired'],
gmtStart: json['gmtStart'],
hasClearPwd: json['hasClearPwd'],
optUid: json['optUid'],
pwd: json['pwd'],
pwdId: json['pwdId'],
pwdName: json['pwdName'],
pwdTypeCode: json['pwdTypeCode'],
revokedPwdName: json['revokedPwdName'],
status: json['status'],
);
}
// Method to convert a Password object to a JSON map
Map<String, dynamic> toJson() {
return {
'gmtCreate': gmtCreate,
'gmtExpired': gmtExpired,
'gmtStart': gmtStart,
'hasClearPwd': hasClearPwd,
'optUid': optUid,
'pwd': pwd,
'pwdId': pwdId,
'pwdName': pwdName,
'pwdTypeCode': pwdTypeCode,
'revokedPwdName': revokedPwdName,
'status': status,
};
}
}

View File

@ -0,0 +1,69 @@
class OfflineTemporaryPassword {
dynamic effectiveTime;
dynamic invalidTime;
dynamic offlineTempPassword;
dynamic offlineTempPasswordId;
dynamic offlineTempPasswordName;
OfflineTemporaryPassword({
required this.effectiveTime,
required this.invalidTime,
required this.offlineTempPassword,
required this.offlineTempPasswordId,
required this.offlineTempPasswordName,
});
factory OfflineTemporaryPassword.fromJson(Map<String, dynamic> json) {
return OfflineTemporaryPassword(
effectiveTime: json['effective_time'],
invalidTime: json['invalid_time'],
offlineTempPassword: json['offline_temp_password'],
offlineTempPasswordId: json['offline_temp_password_id'],
offlineTempPasswordName: json['offline_temp_password_name'],
);
}
Map<String, dynamic> toJson() {
return {
'effective_time': effectiveTime,
'invalid_time': invalidTime,
'offline_temp_password': offlineTempPassword,
'offline_temp_password_id': offlineTempPasswordId,
'offline_temp_password_name': offlineTempPasswordName,
};
}
}
class ApiResponse {
int statusCode;
bool success;
String message;
OfflineTemporaryPassword data;
ApiResponse({
required this.statusCode,
required this.success,
required this.message,
required this.data,
});
factory ApiResponse.fromJson(Map<String, dynamic> json) {
return ApiResponse(
statusCode: json['statusCode'],
success: json['success'],
message: json['message'],
data: OfflineTemporaryPassword.fromJson(json['data']['result']),
);
}
Map<String, dynamic> toJson() {
return {
'statusCode': statusCode,
'success': success,
'message': message,
'data': {
'result': data.toJson(),
},
};
}
}

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

@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
class HourPickerDialog extends StatefulWidget {
final TimeOfDay initialTime;
HourPickerDialog({required this.initialTime});
@override
_HourPickerDialogState createState() => _HourPickerDialogState();
}
class _HourPickerDialogState extends State<HourPickerDialog> {
late int _selectedHour;
bool _isPm = false;
@override
void initState() {
super.initState();
_selectedHour = widget.initialTime.hour > 12 ? widget.initialTime.hour - 12 : widget.initialTime.hour;
_isPm = widget.initialTime.period == DayPeriod.pm;
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Select Hour'),
content: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DropdownButton<int>(
value: _selectedHour,
items: List.generate(12, (index) {
int displayHour = index + 1;
return DropdownMenuItem(
value: displayHour,
child: Text(displayHour.toString()),
);
}),
onChanged: (value) {
setState(() {
_selectedHour = value!;
});
},
),
SizedBox(width: 16.0),
DropdownButton<bool>(
value: _isPm,
items: [
DropdownMenuItem(
value: false,
child: Text('AM'),
),
DropdownMenuItem(
value: true,
child: Text('PM'),
),
],
onChanged: (value) {
setState(() {
_isPm = value!;
});
},
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
child: Text('Cancel'),
),
TextButton(
onPressed: () {
int hour = _isPm ? _selectedHour + 12 : _selectedHour;
Navigator.of(context).pop(TimeOfDay(hour: hour, minute: 0));
},
child: Text('OK'),
),
],
);
}
}
Future<TimeOfDay?> showHourPicker({
required BuildContext context,
required TimeOfDay initialTime,
}) {
return showDialog<TimeOfDay>(
context: context,
builder: (context) => HourPickerDialog(initialTime: initialTime),
);
}

View File

@ -0,0 +1,116 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class NameTimeWidget extends StatelessWidget {
const NameTimeWidget({super.key});
@override
Widget build(BuildContext context) {
return DefaultContainer(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: const BodyMedium(
text: 'Password Name',
fontWeight: FontWeight.normal,
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context)
.passwordNameController,
decoration: const InputDecoration(
hintText: 'Enter The Name',
hintStyle: TextStyle(
fontSize: 14, color: ColorsManager.textGray)),
)),
],
),
Column(
children: [
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Effective Time',
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeOnlinePasswordEvent(context: context, isEffective: true));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).effectiveTime,
style: TextStyle(fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context).effectiveTime ==
'Select Time'
? ColorsManager.textGray
: null),
),
)),
],),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Expiration Time',
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(
SelectTimeOnlinePasswordEvent(
context: context, isEffective: false));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).expirationTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context).expirationTime == 'Select Time'
? ColorsManager.textGray
: null),
),
),
),
],
),
),
],
),
],
));
}
}

View File

@ -0,0 +1,224 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.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/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/repeat_widget.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/door_lock_button.dart';
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/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class OfflineOneTimePasswordPage extends StatelessWidget {
final String? deviceId;
final String? type;
const OfflineOneTimePasswordPage({super.key, this.deviceId, this.type});
@override
Widget build(BuildContext context) {
bool isRepeat = false;
bool generated = false;
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
if (state is FailedState) {
CustomSnackBar.displaySnackBar(
state.errorMessage
);
}
if (state is IsRepeatState){
isRepeat = state.repeat;
}
if (state is GeneratePasswordOneTimestate ){
generated = state.generated;
}
}, builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Create One-Time Password',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
leading: IconButton(
onPressed: () {
Navigator.of(context).pop(true);
},
icon: const Icon(Icons.arrow_back)
),
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyMedium(
text: 'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
const SizedBox(
height: 20,
),
const BodyMedium(
text: '7-Digit Password',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:smartDoorBloc.passwordController.text.isEmpty?
List.generate(10, (index) {
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 4.0,vertical: 15),
child: Icon(
Icons.circle,
size: 20.0,
color: Colors.black,
),
);
}) :[
Expanded(
child: Row(
children: [
Expanded(
child: BodyLarge(
style: const TextStyle(
color: ColorsManager.primaryColor,
fontWeight: FontWeight.bold,
letterSpacing: 8.0 ,
fontSize: 25,
wordSpacing: 2),
textAlign: TextAlign.center,
text: smartDoorBloc.passwordController.text,
fontSize: 23,
),),
IconButton(
onPressed: () async {
await Clipboard.setData(ClipboardData(
text: smartDoorBloc.passwordController.text));
},
icon: const Icon(Icons.copy)
),
],
),
),
],
)),
const SizedBox(
width: 10,
),
],
),
if(smartDoorBloc.passwordController.text.isNotEmpty)
Column(
children: [
const Divider(
color: ColorsManager.graysColor,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: const BodyMedium(
text: 'Password Name',
fontWeight: FontWeight.normal,
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context).passwordNameController,
decoration: const InputDecoration(
hintText: 'Enter The Name',
hintStyle: TextStyle(
fontSize: 14, color: ColorsManager.textGray)),
)),
],
),
],
),
],
),
),
const SizedBox(
height: 20,
),
const BodyMedium(
textAlign: TextAlign.center,
text: 'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
// NameTimeWidget(type:type!),
const SizedBox(
height: 20,
),
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width/1.5,
child: DoorLockButton(
isDone: generated,
isLoading: smartDoorBloc.isSavingPassword ,
borderRadius: 30,
backgroundColor:ColorsManager.primaryColor ,
onPressed: () async {
if(generated==false){
smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context));
}else{
if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent());
}
Navigator.of(context).pop(true);
}
},
child: const BodyMedium(
text: 'Obtain Password',
fontWeight: FontWeight.bold,
fontColor: Colors.white,
),),
),
),
const SizedBox(
height: 20,
),
isRepeat? const RepeatWidget():const SizedBox(),
const SizedBox(
height: 40,
)
],
),
),
);
}));
}
}

View File

@ -1,4 +1,3 @@
import 'package:day_picker/day_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -7,6 +6,8 @@ import 'package:pin_code_fields/pin_code_fields.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/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/name_time_widget.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/repeat_widget.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
@ -14,15 +15,15 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dar
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/font_manager.dart';
import 'package:time_picker_spinner/time_picker_spinner.dart';
class CreateTemporaryPassword extends StatelessWidget {
final String? deviceId;
final String? type;
const CreateTemporaryPassword({super.key, this.deviceId, this.type});
@override
Widget build(BuildContext context) {
bool isRepeat = false;
bool generated = false;
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(listener: (context, state) {
@ -34,7 +35,14 @@ class CreateTemporaryPassword extends StatelessWidget {
),
);
}
if (state is IsRepeatState){
isRepeat = state.repeat;
}
if (state is GeneratePasswordOneTimestate ){
generated = state.generated;
}
}, builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
@ -46,360 +54,143 @@ class CreateTemporaryPassword extends StatelessWidget {
),
leading: IconButton(
onPressed: () {
Navigator.of(context).pop('UpdatePage');
Navigator.of(context).pop(true);
},
icon: const Icon(Icons.arrow_back)
),
actions: [
actions:
type == 'Online Password'?[
TextButton(
onPressed: () {
BlocProvider.of<SmartDoorBloc>(context)
.add(SavePasswordEvent(context: context));
smartDoorBloc.add(SavePasswordEvent(context: context));
},
child: const Text('Save')
)
],
]:null,
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyMedium(
text: 'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
const SizedBox(
height: 20,
),
const BodyMedium(
text: '7-Digit Password',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
flex: 2,
child: PinCodeTextField(
onCompleted: (value) {
if (value.split('').every((char) => char == '1')) {
BlocProvider.of<SmartDoorBloc>(context).passwordController.clear();
CustomSnackBar.displaySnackBar('All characters cannot be 1.');
}
},
autoDisposeControllers: false,
keyboardType: TextInputType.phone,
length: 7,
enabled: true,
obscureText: false,
animationType: AnimationType.fade,
pinTheme: PinTheme(
shape: PinCodeFieldShape.underline,
fieldHeight: 45,
fieldWidth: 20,
activeFillColor: Colors.white,
disabledColor: Colors.grey,
activeColor: Colors.grey,
errorBorderColor: Colors.grey,
inactiveColor: Colors.grey,
inactiveFillColor: Colors.grey,
selectedColor: Colors.grey),
animationDuration: const Duration(milliseconds: 300),
backgroundColor: Colors.white,
enableActiveFill: false,
controller: BlocProvider.of<SmartDoorBloc>(context).passwordController,
appContext: context,
)),
const SizedBox(
width: 10,
),
Flexible(
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context)
.add(GeneratePasswordEvent());
},
child: const BodyMedium(
text: 'Generate Randomly',
fontWeight: FontWeight.bold,
fontColor: ColorsManager.primaryColor,
)),
)
],
),
),
BlocProvider.of<SmartDoorBloc>(context).passwordController.text.isNotEmpty
? TextButton(
onPressed: () async {
await Clipboard.setData(ClipboardData(
text: BlocProvider.of<SmartDoorBloc>(context)
.passwordController
.text));
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyMedium(
text: 'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
const SizedBox(
height: 20,
),
const BodyMedium(
text: '7-Digit Password',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: type == 'Online Password'?0:25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
flex: 2,
child: PinCodeTextField(
onCompleted: (value) {
if (value.split('').every((char) => char == '1')) {
smartDoorBloc.passwordController.clear();
CustomSnackBar.displaySnackBar('All characters cannot be 1.');
}
},
child: const Text('Copy'))
: const SizedBox(),
const SizedBox(
height: 20,
),
DefaultContainer(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: const BodyMedium(
text: 'Password Name',
fontWeight: FontWeight.normal,
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context)
.passwordNameController,
decoration: const InputDecoration(
hintText: 'Enter The Name',
hintStyle: TextStyle(
fontSize: 14, color: ColorsManager.textGray)),
)),
],
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Effective Time',
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(
SelectTimeEvent(
context: context, isEffective: true));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).effectiveTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context)
.effectiveTime ==
'Select Time'
? ColorsManager.textGray
: null),
),
)),
],
),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Expiration Time',
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(
SelectTimeEvent(
context: context, isEffective: false));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).expirationTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context)
.expirationTime ==
'Select Time'
? ColorsManager.textGray
: null),
),
),
),
],
),
),
],
)),
const SizedBox(
height: 20,
),
if (type == 'Online Password')
DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: 'Repeat',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: BlocProvider.of<SmartDoorBloc>(context).repeat,
onChanged: (value) {
BlocProvider.of<SmartDoorBloc>(context)
.add(ToggleRepeatEvent());
},
applyTheme: true,
)),
),
autoDisposeControllers: false,
keyboardType: TextInputType.phone,
length: 7,
// enabled:type == 'Online Password'? true:false,
obscureText: false,
animationType: AnimationType.fade,
pinTheme: PinTheme(
shape: PinCodeFieldShape.underline,
fieldHeight: 45,
fieldWidth: 20,
activeFillColor: Colors.white,
disabledColor: Colors.grey,
activeColor: Colors.grey,
errorBorderColor: Colors.grey,
inactiveColor: Colors.grey,
inactiveFillColor: Colors.grey,
selectedColor: Colors.grey),
animationDuration: const Duration(milliseconds: 300),
backgroundColor: Colors.white,
enableActiveFill: false,
controller: smartDoorBloc.passwordController,
appContext: context,
)),
const SizedBox(
width: 10,
),
const SizedBox(
height: 20,
),
BlocProvider.of<SmartDoorBloc>(context).repeat
? DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context)
.add(const SetStartEndTimeEvent(val: true));
},
child: BodyMedium(
text: 'Start',
fontColor: BlocProvider.of<SmartDoorBloc>(context)
.isStartEndTime ==
false
? Colors.black
: Colors.blue,
fontSize: 18,
),
),
InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context)
.add(const SetStartEndTimeEvent(val: false));
},
child: BodyMedium(
text: 'End',
fontColor: BlocProvider.of<SmartDoorBloc>(context)
.isStartEndTime
? Colors.black
: Colors.blue,
fontSize: 18,
),
)
],
),
),
const Divider(
color: ColorsManager.graysColor,
),
Container(
height: 110,
child: BlocProvider.of<SmartDoorBloc>(context).isStartEndTime
? TimePickerSpinner(
time:
BlocProvider.of<SmartDoorBloc>(context).startTime,
is24HourMode: false,
itemHeight: 40,
normalTextStyle: const TextStyle(
color: Colors.grey,
fontSize: 24,
),
highlightedTextStyle:
const TextStyle(fontSize: 30, color: Colors.blue),
onTimeChange: (time) {
BlocProvider.of<SmartDoorBloc>(context).add(
ChangeTimeEvent(
val: time,
isStartEndTime:
BlocProvider.of<SmartDoorBloc>(context)
.isStartEndTime));
},
)
: Container(
child: TimePickerSpinner(
time:
BlocProvider.of<SmartDoorBloc>(context).endTime,
is24HourMode: false,
itemHeight: 40,
normalTextStyle: const TextStyle(
color: Colors.grey,
fontSize: 24,
),
highlightedTextStyle: const TextStyle(
fontSize: 30, color: Colors.blue),
onTimeChange: (time) {
BlocProvider.of<SmartDoorBloc>(context).add(
ChangeTimeEvent(
val: time,
isStartEndTime:
BlocProvider.of<SmartDoorBloc>(
context)
.isStartEndTime));
},
),
),
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(height: 20),
SelectWeekDays(
width: MediaQuery.of(context).size.width / 1,
fontSize: 18,
fontWeight: FontWeight.w600,
days: BlocProvider.of<SmartDoorBloc>(context).days,
border: false,
selectedDayTextColor: Colors.black,
unSelectedDayTextColor: Colors.grey,
boxDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Colors.white),
onSelect: (values) {
BlocProvider.of<SmartDoorBloc>(context).selectedDay =
values;
},
),
],
))
: const SizedBox(),
const SizedBox(
height: 40,
)
],
if(type == 'Online Password')
Flexible(
child: InkWell(
onTap: () {
smartDoorBloc.add(GeneratePasswordEvent());
},
child: const BodyMedium(
text: 'Generate Randomly',
fontWeight: FontWeight.bold,
fontColor: ColorsManager.primaryColor,
)),
)
],
),
),
),
if(smartDoorBloc.passwordController.text.isNotEmpty)
TextButton(
onPressed: () async {
await Clipboard.setData(ClipboardData(
text: smartDoorBloc.passwordController.text));
},
child: const Text('Copy')
),
const SizedBox(
height: 20,
),
NameTimeWidget(),
const SizedBox(
height: 20,
),
DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const BodyMedium(
text: 'Repeat',
fontWeight: FontWeight.normal,
),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: smartDoorBloc.repeat,
onChanged: (value) {
smartDoorBloc.add(ToggleRepeatEvent());
},
applyTheme: true,
)),
),
) ,
const SizedBox(
height: 20,
),
isRepeat? const RepeatWidget():const SizedBox(),
const SizedBox(
height: 40,
)
],
),
),
);
}));
}

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

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/model/offline_password_model.dart';
import 'package:syncrow_app/features/devices/model/temporary_password_model.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart';
@ -7,13 +8,15 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class DoorDialog extends StatefulWidget {
final String title;
final TemporaryPassword value;
final String? title;
final TemporaryPassword? temporaryPassword;
final OfflinePasswordModel? offline;
const DoorDialog({
super.key,
required this.title,
required this.value,
this.title,
this.offline,
this.temporaryPassword,
});
@override
@ -28,16 +31,18 @@ class DoorDialogState extends State<DoorDialog> {
@override
Widget build(BuildContext context) {
final effectiveTime = widget.temporaryPassword?.effectiveTime ??int.parse( widget.offline?.gmtStart);
final invalidTime = widget.temporaryPassword?.invalidTime ?? int.parse(widget.offline?.gmtExpired);
final DateTime effectiveDateTime =
DateTime.fromMillisecondsSinceEpoch(widget.value.effectiveTime * 1000, isUtc: false);
DateTime.fromMillisecondsSinceEpoch(effectiveTime! * 1000, isUtc: false);
String formattedDateEffectiveTime = DateFormat('yyyy-MM-dd').format(effectiveDateTime);
String formattedTimeEffectiveTime = DateFormat('HH:mm:ss').format(effectiveDateTime);
String formattedTimeEffectiveTime = DateFormat('hh:mm a').format(effectiveDateTime);
final DateTime expiredDateTime =
DateTime.fromMillisecondsSinceEpoch(widget.value.invalidTime * 1000, isUtc: false);
DateTime.fromMillisecondsSinceEpoch(invalidTime! * 1000, isUtc: false);
String formattedDateExpiredDateTime = DateFormat('yyyy-MM-dd').format(expiredDateTime);
String formattedTimeExpiredDateTime = DateFormat('HH:mm:ss').format(expiredDateTime);
String formattedTimeExpiredDateTime = DateFormat('hh:mm a').format(expiredDateTime);
return Dialog(
child: Container(
decoration: BoxDecoration(
@ -49,7 +54,7 @@ class DoorDialogState extends State<DoorDialog> {
mainAxisSize: MainAxisSize.min,
children: [
BodyMedium(
text: widget.title,
text: widget.title ?? '',
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontsManager.extraBold,
@ -111,6 +116,7 @@ class DoorDialogState extends State<DoorDialog> {
width: double.infinity,
color: ColorsManager.greyColor,
),
widget.temporaryPassword?.effectiveTime!=null?
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
@ -142,6 +148,27 @@ class DoorDialogState extends State<DoorDialog> {
),
),
],
):
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
height: 50,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Center(
child: BodyMedium(
text: 'Cancel',
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
),
),
),
),
],
)
],
),

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

@ -0,0 +1,288 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.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/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/repeat_widget.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/door_lock_button.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/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class CreateOfflineTimeLimitPasswordPage extends StatelessWidget {
final String? deviceId;
final String? type;
const CreateOfflineTimeLimitPasswordPage({super.key, this.deviceId, this.type});
@override
Widget build(BuildContext context) {
bool isRepeat = false;
bool generated = false;
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
CustomSnackBar.displaySnackBar(
state.errorMessage
);
}
if (state is IsRepeatState) {
isRepeat = state.repeat;
}
if (state is GeneratePasswordOneTimestate) {
generated = state.generated;
}
}, builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Create Time-Limited Password',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
leading: IconButton(
onPressed: () {
Navigator.of(context).pop(true);
},
icon: const Icon(Icons.arrow_back)),
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const BodyMedium(
text:
'Save the password immediately. The password is not displayed in the app.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
const SizedBox(
height: 20,
),
DefaultContainer(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 15),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: smartDoorBloc.passwordController.text.isEmpty ?
List.generate(10, (index) {
return const Padding(
padding: EdgeInsets.symmetric(
horizontal: 4.0,
vertical: 15),
child: Icon(
Icons.circle,
size: 20.0,
color: Colors.black,
),
);
}) : [
Expanded(
child: Row(
children: [
Expanded(
child: BodyLarge(
style: const TextStyle(
color: ColorsManager.primaryColor,
fontWeight: FontWeight.bold,
letterSpacing: 8.0,
fontSize: 25,
wordSpacing: 2),
textAlign: TextAlign.center,
text: smartDoorBloc.passwordController.text,
fontSize: 25,
),
),
IconButton(
onPressed: () async {
await Clipboard.setData(
ClipboardData(text: smartDoorBloc.passwordController.text)
);
},
icon: const Icon(Icons.copy)),
],
),
),
],
)),
const SizedBox(
width: 10,
),
],
),
DefaultContainer(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: const BodyMedium(
text: 'Password Name',
fontWeight: FontWeight.normal,
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 2.6,
child: TextFormField(
controller: BlocProvider.of<SmartDoorBloc>(context).passwordNameController,
decoration:
const InputDecoration(
hintText: 'Enter The Name',
hintStyle: TextStyle(
fontSize: 14,
color: ColorsManager.textGray)
),
)),
],
),
Column(
children: [
const Divider(color: ColorsManager.graysColor,),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Effective Time',
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeEvent(context: context, isEffective: true));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).effectiveTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context).effectiveTime ==
'Select Time' ? ColorsManager.textGray : null),
),
)),],
),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const Expanded(
child: BodyMedium(
text: 'Expiration Time',
fontWeight: FontWeight.normal,
),
),
SizedBox(
width: MediaQuery.of(context).size.width / 3.5,
child: InkWell(
onTap: () {
BlocProvider.of<SmartDoorBloc>(context).add(SelectTimeEvent(
context: context,
isEffective: false));
},
child: Text(
BlocProvider.of<SmartDoorBloc>(context).expirationTime,
style: TextStyle(
fontSize: 14,
color: BlocProvider.of<SmartDoorBloc>(context)
.expirationTime == 'Select Time' ? ColorsManager
.textGray : null),
),
),
),
],
),
),
],
),
],
)),
],
),
),
const SizedBox(
height: 20,
),
const BodyMedium(
textAlign: TextAlign.center,
text: 'Use the time-limited password at least once within 24 hours after the password takes effect. Otherwise, the password becomes invalid.',
fontWeight: FontWeight.normal,
fontColor: ColorsManager.grayColor,
),
// NameTimeWidget(type:type!),
const SizedBox(
height: 20,
),
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width / 1.5,
child: DoorLockButton(
isDone: generated,
isLoading: smartDoorBloc.isSavingPassword,
borderRadius: 30,
backgroundColor: ColorsManager.primaryColor,
onPressed: () async {
if (generated == false) {
smartDoorBloc.add(GenerateAndSavePasswordTimeLimitEvent(context: context));
} else {
if(smartDoorBloc.passwordNameController.text.isNotEmpty){
smartDoorBloc.add(RenamePasswordEvent());
}
Navigator.of(context).pop(true);
}
},
child: const BodyMedium(
text: 'Obtain Password',
fontWeight: FontWeight.bold,
fontColor: Colors.white,
),
),
),
),
const SizedBox(
height: 20,
),
isRepeat ? const RepeatWidget() : const SizedBox(),
const SizedBox(
height: 40,
)
],
),
),
);
}));
}
}

View File

@ -0,0 +1,111 @@
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/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/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/offline_one_time_password_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_dialog.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class OnetimePasswordPage extends StatelessWidget {
final String? deviceId;
const OnetimePasswordPage({super.key, this.deviceId,});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialOneTimePassword( )),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.errorMessage),
backgroundColor: Colors.red,
),
);
}
},
builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => OfflineOneTimePasswordPage(deviceId: deviceId, )
)).then((result) {
if(result!=null){
smartDoorBloc.add(InitialOneTimePassword());
smartDoorBloc.add(InitialOneTimePassword());
}
});
},
icon: const Icon(Icons.add)
)
],
child: Builder(
builder: (context) {
return state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Center(
child: smartDoorBloc.oneTimePasswords!.isNotEmpty
? ListView.builder(
itemCount: smartDoorBloc.oneTimePasswords!.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text: 'Password Name: ${smartDoorBloc.oneTimePasswords![index].pwdName}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return DoorDialog(
title: 'Password Information',
offline: smartDoorBloc.oneTimePasswords![index],
);
},
);
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
),
);
},
) : Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.noValidPasswords),
const SizedBox(
height: 10,
),
const BodyMedium(text: 'No Valid Passwords')
],
),
);
},
));
})
);
}
}

View File

@ -0,0 +1,125 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class RepeatWidget extends StatelessWidget {
const RepeatWidget({
super.key,
});
@override
Widget build(BuildContext context) {
return BlocBuilder<SmartDoorBloc, SmartDoorState>(
builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: Column(children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
smartDoorBloc.add(const SetStartEndTimeEvent(val: true));
},
child: BodyMedium(
text: 'Start',
fontColor: smartDoorBloc.isStartEndTime == false
? Colors.black
: Colors.blue,
fontSize: 18,
),
),
InkWell(
onTap: () {
smartDoorBloc.add(const SetStartEndTimeEvent(val: false));
},
child: BodyMedium(
text: 'End',
fontColor: smartDoorBloc.isStartEndTime
? Colors.black
: Colors.blue,
fontSize: 18,
),
)
],
),
),
const Divider(
color: ColorsManager.graysColor,
),
smartDoorBloc.isStartEndTime
? Container(
height: 110,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.time,
initialDateTime:smartDoorBloc.startTime,
onDateTimeChanged: (startTime) {
smartDoorBloc.add(ChangeTimeEvent(val: startTime, isStartEndTime: true));
},
)
):SizedBox(
height: 110,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.time,
initialDateTime:smartDoorBloc.endTime,
onDateTimeChanged: (endTime) {
smartDoorBloc.add(ChangeTimeEvent(val: endTime, isStartEndTime: false));
},
)
),
const Divider(
color: ColorsManager.graysColor,
),
const SizedBox(height: 20),
SizedBox(
height: MediaQuery.of(context).size.height *0.10,
child: ListView(
scrollDirection: Axis.horizontal,
children: smartDoorBloc.days.map((day) {
bool isSelected = smartDoorBloc.selectedDays.contains(day['key']);
return Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () {
smartDoorBloc.add(ToggleDaySelectionEvent(key:day['key']!));
},
child: Container(
width: 70,
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
decoration: BoxDecoration(
border: Border.all(
color: isSelected?
Colors.black:ColorsManager.grayColor
),
color: Colors.transparent,
borderRadius: BorderRadius.circular(55),
),
child: Center(
child: Text(
day['day']!,
style: TextStyle(
fontSize: 18,
color: isSelected ? Colors.black : ColorsManager.grayColor,
),
),
),
),
),
);
}).toList(),
)
)
]));
});
}
}

View File

@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/onetime_password_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/timelimited_password_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/view_temporary_password.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
@ -10,7 +12,7 @@ import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class TemporaryPasswordPage extends StatelessWidget {
final String? deviceId;
final String? deviceId;
const TemporaryPasswordPage({super.key,this.deviceId});
@override
@ -40,13 +42,17 @@ class TemporaryPasswordPage extends StatelessWidget {
child:ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(
Assets.timeLimitedPasswordIcon),
Assets.timeLimitedPasswordIcon),
title: const BodyMedium(
text: 'Time-Limited Password',
fontWeight: FontWeight.normal,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ViewTemporaryPassword(deviceId:deviceId,type:'Online Password'),));
Navigator.of(context).push(MaterialPageRoute(builder: (context) =>
ViewTemporaryPassword(
deviceId:deviceId,
type:'Online Password'),
));
},
trailing: const Icon(
Icons.arrow_forward_ios,
@ -57,7 +63,6 @@ class TemporaryPasswordPage extends StatelessWidget {
),
],
),
const SizedBox(height: 10),
Column(
mainAxisAlignment: MainAxisAlignment.start,
@ -75,46 +80,45 @@ class TemporaryPasswordPage extends StatelessWidget {
),
const SizedBox(height: 10),
DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(children: [
ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.oneTimePassword),
title:
const BodyMedium(
text: 'One-Time Password',
fontWeight: FontWeight.normal,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ViewTemporaryPassword(deviceId:deviceId,type:'One-Time'),));
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
const Divider(color:ColorsManager.graysColor,),
ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(
Assets.timeLimitedPassword),
title: const BodyMedium(
text: 'Time-Limited Password',
fontWeight: FontWeight.normal,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ViewTemporaryPassword(deviceId:deviceId,type:'Time-Limited'),));
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
],)
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
children: [
ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.oneTimePassword),
title:
const BodyMedium(
text: 'One-Time Password',
fontWeight: FontWeight.normal,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => OnetimePasswordPage(deviceId:deviceId,),));
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
const Divider(color:ColorsManager.graysColor,),
ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(
Assets.timeLimitedPassword),
title: const BodyMedium(
text: 'Time-Limited Password',
fontWeight: FontWeight.normal,
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => TimeLimitedPasswordPage(deviceId:deviceId,),));
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
],)
),
],
),

View File

@ -0,0 +1,105 @@
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/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/bloc/smart_door_bloc/smart_door_state.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/offline_timeLimit_password_page.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'door_dialog.dart';
class TimeLimitedPasswordPage extends StatelessWidget {
final String? deviceId;
const TimeLimitedPasswordPage({super.key, this.deviceId});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialTimeLimitPassword()),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
CustomSnackBar.displaySnackBar(
state.errorMessage
);
}
},
builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,)
)).then((result) {
smartDoorBloc.add(InitialTimeLimitPassword());
smartDoorBloc.add(InitialTimeLimitPassword());
});
},
icon: const Icon(Icons.add)
)
],
child: Builder(
builder: (context) {
return state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Center(
child: smartDoorBloc.timeLimitPasswords!.isNotEmpty
? ListView.builder(
itemCount: smartDoorBloc.timeLimitPasswords!.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text: 'Password Name: ${smartDoorBloc.timeLimitPasswords![index].pwdName}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return DoorDialog(
title: 'Password Information',
offline: smartDoorBloc.timeLimitPasswords![index],
);
},
);
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
),
);
},
) : Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.noValidPasswords),
const SizedBox(
height: 10,
),
const BodyMedium(text: 'No Valid Passwords')
],
),
);
},
));
})
);
}
}

View File

@ -20,8 +20,7 @@ class ViewTemporaryPassword extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) =>
SmartDoorBloc(deviceId: deviceId!)..add(InitialPasswordsPage(type:type )),
create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialPasswordsPage( )),
child: BlocConsumer<SmartDoorBloc, SmartDoorState>(
listener: (context, state) {
if (state is FailedState) {
@ -32,84 +31,86 @@ class ViewTemporaryPassword extends StatelessWidget {
),
);
}
}, builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CreateTemporaryPassword(deviceId: deviceId, type: type),
)).then((result) {
if (result != null && result) {
smartDoorBloc.add(InitialPasswordsPage(type:type ));
}
});
},
icon: const Icon(Icons.add))
],
child: Builder(
builder: (context) {
return state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Center(
child: smartDoorBloc.temporaryPasswords!.isNotEmpty
? ListView.builder(
itemCount: smartDoorBloc.temporaryPasswords!.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(
Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text:
'Password Name: ${smartDoorBloc.temporaryPasswords![index].name}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return DoorDialog(
title: 'Password Information',
value: smartDoorBloc.temporaryPasswords![index],
);
},
);
if(result=='delete'){
smartDoorBloc.add(DeletePasswordEvent(passwordId: smartDoorBloc.temporaryPasswords![index].id.toString()));
}
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
),
);
},
},
builder: (context, state) {
final smartDoorBloc = BlocProvider.of<SmartDoorBloc>(context);
return DefaultScaffold(
title: 'Passwords',
actions: [
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) =>
CreateTemporaryPassword(deviceId: deviceId, type: type))).then((result) {
if (result != null && result) {
smartDoorBloc.add(InitialPasswordsPage());
smartDoorBloc.add(InitialPasswordsPage());
}
});
},
icon: const Icon(Icons.add)
)
: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.noValidPasswords),
const SizedBox(
height: 10,
],
child: Builder(
builder: (context) {
return state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Center(
child: smartDoorBloc.temporaryPasswords!.isNotEmpty
? ListView.builder(
itemCount: smartDoorBloc.temporaryPasswords!.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DefaultContainer(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: SvgPicture.asset(
Assets.timeLimitedPasswordIcon),
title: BodyMedium(
text: 'Password Name: ${smartDoorBloc.temporaryPasswords![index].name}',
fontWeight: FontWeight.normal,
),
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return DoorDialog(
title: 'Password Information',
temporaryPassword: smartDoorBloc.temporaryPasswords![index],
);
},
);
if(result=='delete'){
smartDoorBloc.add(DeletePasswordEvent(passwordId: smartDoorBloc.temporaryPasswords![index].id.toString()));
}
},
trailing: const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 15,
),
),
),
);
},
)
: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(Assets.noValidPasswords),
const SizedBox(
height: 10,
),
const BodyMedium(text: 'No Valid Passwords')
],
),
const BodyMedium(text: 'No Valid Passwords')
],
),
);
},
));
}));
);
},
));
})
);
}
}

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

@ -9,6 +9,16 @@ import 'package:syncrow_app/features/scene/model/create_automation_model.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
final daysMap = {
'Sun': 'S',
'Mon': 'M',
'Tue': 'T',
'Wed': 'W',
'Thu': 'T',
'Fri': 'F',
'Sat': 'S',
};
EffectPeriodBloc() : super(EffectPeriodState.initial()) {
on<SetPeriod>(_onSetPeriod);
on<ToggleDay>(_onToggleDay);
@ -43,20 +53,17 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
break;
}
BlocProvider.of<CreateSceneBloc>(
NavigationService.navigatorKey.currentContext!)
.add(EffectiveTimePeriodEvent(EffectiveTime(
start: startTime, end: endTime, loops: state.selectedDaysBinary)));
BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
EffectiveTimePeriodEvent(
EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
emit(state.copyWith(
selectedPeriod: event.period,
customStartTime: startTime,
customEndTime: endTime));
selectedPeriod: event.period, customStartTime: startTime, customEndTime: endTime));
}
void _onToggleDay(ToggleDay event, Emitter<EffectPeriodState> emit) {
final daysList = state.selectedDaysBinary.split('');
final dayIndex = _getDayIndex(event.day);
final dayIndex = getDayIndex(event.day);
if (daysList[dayIndex] == '1') {
daysList[dayIndex] = '0';
} else {
@ -65,9 +72,8 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
final newDaysBinary = daysList.join();
emit(state.copyWith(selectedDaysBinary: newDaysBinary));
BlocProvider.of<CreateSceneBloc>(
NavigationService.navigatorKey.currentContext!)
.add(EffectiveTimePeriodEvent(EffectiveTime(
BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
EffectiveTimePeriodEvent(EffectiveTime(
start: state.customStartTime ?? '00:00',
end: state.customEndTime ?? '23:59',
loops: newDaysBinary)));
@ -89,37 +95,31 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
period = EnumEffectivePeriodOptions.custom;
}
emit(state.copyWith(
customStartTime: startTime,
customEndTime: endTime,
selectedPeriod: period));
emit(
state.copyWith(customStartTime: startTime, customEndTime: endTime, selectedPeriod: period));
BlocProvider.of<CreateSceneBloc>(
NavigationService.navigatorKey.currentContext!)
.add(EffectiveTimePeriodEvent(EffectiveTime(
start: startTime, end: endTime, loops: state.selectedDaysBinary)));
BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
EffectiveTimePeriodEvent(
EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
}
void _onResetEffectivePeriod(
ResetEffectivePeriod event, Emitter<EffectPeriodState> emit) {
void _onResetEffectivePeriod(ResetEffectivePeriod event, Emitter<EffectPeriodState> emit) {
emit(state.copyWith(
selectedPeriod: EnumEffectivePeriodOptions.allDay,
customStartTime: '00:00',
customEndTime: '23:59',
selectedDaysBinary: '1111111'));
BlocProvider.of<CreateSceneBloc>(
NavigationService.navigatorKey.currentContext!)
.add(EffectiveTimePeriodEvent(
EffectiveTime(start: '00:00', end: '23:59', loops: '1111111')));
BlocProvider.of<CreateSceneBloc>(NavigationService.navigatorKey.currentContext!).add(
EffectiveTimePeriodEvent(EffectiveTime(start: '00:00', end: '23:59', loops: '1111111')));
}
void _onResetDays(ResetDays event, Emitter<EffectPeriodState> emit) {
emit(state.copyWith(selectedDaysBinary: '1111111'));
}
int _getDayIndex(String day) {
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
int getDayIndex(String day) {
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
return days.indexOf(day);
}

View File

@ -13,16 +13,7 @@ class RepeatDays extends StatelessWidget {
@override
Widget build(BuildContext context) {
final daysMap = {
'Mon': 'M',
'Tue': 'T',
'Wed': 'W',
'Thu': 'T',
'Fri': 'F',
'Sat': 'S',
'Sun': 'S',
};
final effectiveBloc = context.read<EffectPeriodBloc>();
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -37,25 +28,22 @@ class RepeatDays extends StatelessWidget {
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: daysMap.entries.map((entry) {
children: effectiveBloc.daysMap.entries.map((entry) {
final day = entry.key;
final abbreviation = entry.value;
final dayIndex = _getDayIndex(day);
final isSelected =
state.selectedDaysBinary[dayIndex] == '1';
final dayIndex = effectiveBloc.getDayIndex(day);
final isSelected = state.selectedDaysBinary[dayIndex] == '1';
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 3.0),
child: GestureDetector(
onTap: () {
context.read<EffectPeriodBloc>().add(ToggleDay(day));
effectiveBloc.add(ToggleDay(day));
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: isSelected
? Colors.grey
: Colors.grey.shade300,
color: isSelected ? Colors.grey : Colors.grey.shade300,
width: 1,
),
),
@ -66,9 +54,7 @@ class RepeatDays extends StatelessWidget {
abbreviation,
style: TextStyle(
fontSize: 16,
color: isSelected
? Colors.grey
: Colors.grey.shade300,
color: isSelected ? Colors.grey : Colors.grey.shade300,
),
),
),
@ -83,8 +69,7 @@ class RepeatDays extends StatelessWidget {
if (state.selectedDaysBinary == '0000000')
BodySmall(
text: 'At least one day must be selected',
style:
context.bodyMedium.copyWith(color: ColorsManager.red),
style: context.bodyMedium.copyWith(color: ColorsManager.red),
),
],
);
@ -93,9 +78,4 @@ class RepeatDays extends StatelessWidget {
],
);
}
int _getDayIndex(String day) {
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
return days.indexOf(day);
}
}

View File

@ -93,7 +93,7 @@ class _SmartSceneSelectTabToRunListState extends State<SmartSceneSelectTabToRunL
.read<SmartSceneSelectBloc>()
.add(SmartSceneEnableEvent(SmartSceneEnable(
entityId: scene.id,
actionExecutor: 'rule_enable',
actionExecutor: 'rule_trigger',
sceneORAutomationName: scene.name,
type: scene.type,
isAutomation: false,
@ -109,7 +109,7 @@ class _SmartSceneSelectTabToRunListState extends State<SmartSceneSelectTabToRunL
});
context.read<SmartSceneSelectBloc>().add(SmartSceneEnableEvent(SmartSceneEnable(
entityId: scene.id,
actionExecutor: 'rule_enable',
actionExecutor: 'rule_trigger',
sceneORAutomationName: scene.name,
type: scene.type,
isAutomation: false,

View File

@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class DoorLockButton extends StatelessWidget {
const DoorLockButton({
super.key,
this.enabled = true,
this.onPressed,
required this.child,
this.isSecondary = false,
this.isLoading = false,
this.isDone = false,
this.customTextStyle,
this.customButtonStyle,
this.backgroundColor,
this.foregroundColor,
this.borderRadius,
this.height,
this.padding,
});
final void Function()? onPressed;
final Widget child;
final double? height;
final bool isSecondary;
final double? borderRadius;
final bool enabled;
final double? padding;
final bool isDone;
final bool isLoading;
final TextStyle? customTextStyle;
final ButtonStyle? customButtonStyle;
final Color? backgroundColor;
final Color? foregroundColor;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: enabled ? onPressed : null,
style: isSecondary
? null
: customButtonStyle ??
ButtonStyle(
textStyle: MaterialStateProperty.all(
customTextStyle ??
context.bodyMedium.copyWith(
fontSize: 16,
color: foregroundColor,
),
),
foregroundColor: MaterialStateProperty.all(
isSecondary
? Colors.black
: enabled
? foregroundColor ?? Colors.white
: Colors.black,
),
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) {
return enabled
? backgroundColor ?? ColorsManager.primaryColor
: Colors.grey;
}),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius ?? 20),
),
),
fixedSize: MaterialStateProperty.all(
const Size.fromHeight(50),
),
padding: MaterialStateProperty.all(
EdgeInsets.all(padding ?? 10),
),
minimumSize: MaterialStateProperty.all(
const Size.fromHeight(50),
),
),
child: SizedBox(
height: height ?? 50,
child: Center(
child: isLoading
? const SizedBox.square(
dimension: 24,
child: CircularProgressIndicator(
color: Colors.white,
),
)
: isDone
? const Text('Done') :child ,
),
),
);
}
}

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,16 +153,6 @@ abstract class ApiEndpoints {
static const String getOneTimeTemporaryPassword =
'/door-lock/temporary-password/offline/one-time/{doorLockUuid}';
//multiple-time offline
static const String addMultipleTimeTemporaryPassword =
'/door-lock/temporary-password/offline/multiple-time/{doorLockUuid}';
static const String getMultipleTimeTemporaryPassword =
'/door-lock/temporary-password/offline/multiple-time/{doorLockUuid}';
//multiple-time offline
static const String deleteTemporaryPassword =
'/door-lock/temporary-password/{doorLockUuid}/{passwordId}';
//user
static const String getUser = '/user/{userUuid}';
@ -179,4 +162,17 @@ abstract class ApiEndpoints {
static const String sendPicture = '/user/profile-picture/{userUuid}';
static const String getRegion = '/region';
static const String getTimezone = '/timezone';
//multiple-time offline
static const String addMultipleTimeTemporaryPassword =
'/door-lock/temporary-password/offline/multiple-time/{doorLockUuid}';
static const String getMultipleTimeTemporaryPassword =
'/door-lock/temporary-password/offline/multiple-time/{doorLockUuid}';
static const String renamePassword =
'/door-lock/temporary-password/{doorLockUuid}/offline/{passwordId}';
//multiple-time offline
static const String deleteTemporaryPassword =
'/door-lock/temporary-password/online/{doorLockUuid}/{passwordId}';
}

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,6 +80,20 @@ class DevicesAPI {
return response;
}
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},
expectedResponseModel: (json) {
return json;
},
);
return response;
}
/// Get Device Functions
static Future<FunctionModel> deviceFunctions(String deviceId) async {
final response = await _httpService.get(
@ -138,14 +163,11 @@ class DevicesAPI {
return response;
}
static Future getTemporaryPasswords(String deviceId, pageType) async {
static Future getTemporaryPasswords(
String deviceId,
) async {
final response = await _httpService.get(
path: pageType == 'One-Time'
? ApiEndpoints.getOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId)
: pageType == 'Online Password'
? ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId)
: ApiEndpoints.getMultipleTimeTemporaryPassword
.replaceAll('{doorLockUuid}', deviceId),
path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
@ -154,37 +176,49 @@ class DevicesAPI {
return response;
}
//create password
static Future getOneTimePasswords(String deviceId) async {
final response = await _httpService.get(
path: ApiEndpoints.getOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
static Future getTimeLimitPasswords(String deviceId) async {
final response = await _httpService.get(
path: ApiEndpoints.getMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
//create password
static Future createPassword({
required String name,
required String password,
required String effectiveTime,
required String invalidTime,
required String deviceId,
required String pageType,
List<Schedule>? scheduleList,
}) async {
String endpointPath;
if (pageType == 'Online Password') {
endpointPath = ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId);
} else if (pageType == 'One-Time') {
endpointPath =
ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId);
} else {
endpointPath =
ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId);
}
Map<String, dynamic> body = {
"name": name,
"password": password,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
};
if (pageType == 'Online Password' && scheduleList != null) {
print('createPassword =$body');
if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
}
final response = await _httpService.post(
path: endpointPath,
path: ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
body: body,
showServerMessage: false,
expectedResponseModel: (json) => json,
@ -192,6 +226,37 @@ class DevicesAPI {
return response;
}
static Future generateOneTimePassword({deviceId}) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
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},
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> deletePassword(
{required String passwordId, required String deviceId}) async {
final response = await _httpService.delete(

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+18
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