Compare commits
25 Commits
automation
...
bugfix/SP-
| Author | SHA1 | Date | |
|---|---|---|---|
| 21c336360c | |||
| fee34703bd | |||
| a92676d6a4 | |||
| 8c5cf2c04e | |||
| 1f02f66916 | |||
| 3ea089425c | |||
| 77d2f54352 | |||
| cff66bb653 | |||
| 022ba53f5d | |||
| bf69399af2 | |||
| a72fc0b466 | |||
| df13840a65 | |||
| e63bf2a2c2 | |||
| b3bb0b9eea | |||
| 032a28d47a | |||
| dcc98445d7 | |||
| 611c515173 | |||
| e733dd9230 | |||
| 8e104aeea7 | |||
| f6fbf452a0 | |||
| 5aec3d37fb | |||
| a32d885e50 | |||
| afe37dd68a | |||
| f83224ce60 | |||
| 0ef2f3b866 |
14
assets/icons/success-white.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Group 284">
|
||||
<g id="Group">
|
||||
<g id="Group_2">
|
||||
<path id="Vector" d="M37.8033 16.3571C37.2313 15.7851 36.3039 15.785 35.7318 16.3572L21.5532 30.5356L14.2681 23.2508C13.6962 22.6788 12.7686 22.6787 12.1966 23.2509C11.6246 23.8229 11.6246 24.7504 12.1966 25.3224L20.5174 33.643C20.8034 33.9291 21.1783 34.072 21.5531 34.072C21.928 34.072 22.3029 33.9291 22.5888 33.6429L37.8033 18.4287C38.3754 17.8567 38.3754 16.9292 37.8033 16.3571Z" fill="white"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group_3">
|
||||
<g id="Group_4">
|
||||
<path id="Vector_2" d="M42.6776 7.32236C37.9558 2.60049 31.6776 0 25 0C18.3223 0 12.0442 2.60049 7.32236 7.32236C2.60039 12.0443 0 18.3224 0 25C0 31.6778 2.60039 37.9559 7.32236 42.6777C12.0441 47.3996 18.3223 50 25 50C31.6777 50 37.9558 47.3996 42.6776 42.6777C47.3995 37.9559 50 31.6778 50 25C50 18.3224 47.3995 12.0443 42.6776 7.32236ZM25 47.0703C12.8304 47.0703 2.92969 37.1696 2.92969 25C2.92969 12.8304 12.8304 2.92969 25 2.92969C37.1696 2.92969 47.0703 12.8304 47.0703 25C47.0703 37.1696 37.1696 47.0703 25 47.0703Z" fill="white"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
116
ios/Podfile.lock
@ -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
|
||||
|
||||
@ -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 = "";
|
||||
|
||||
@ -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"
|
||||
|
||||
|
After Width: | Height: | Size: 321 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 {}
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
63
lib/features/devices/model/offline_password_model.dart
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
69
lib/features/devices/model/offline_temporary_password.dart
Normal 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(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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(
|
||||
|
||||
@ -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,
|
||||
|
||||
92
lib/features/devices/view/widgets/hour_picker_dialog.dart
Normal 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),
|
||||
);
|
||||
}
|
||||
116
lib/features/devices/view/widgets/name_time_widget.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
@ -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!,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
));
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -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')
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
125
lib/features/devices/view/widgets/smart_door/repeat_widget.dart
Normal 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(),
|
||||
)
|
||||
)
|
||||
]));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
),
|
||||
),
|
||||
],)
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -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')
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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')
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
));
|
||||
}));
|
||||
);
|
||||
},
|
||||
));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
),
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
99
lib/features/shared_widgets/door_lock_button.dart
Normal 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 ,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
45
lib/features/shared_widgets/success_dialog.dart
Normal 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),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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";
|
||||
|
||||
}
|
||||
|
||||
@ -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}';
|
||||
}
|
||||
|
||||
@ -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(
|
||||
|
||||
32
pubspec.lock
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||