Compare commits

..

54 Commits

Author SHA1 Message Date
4c8f2c72df Merge branch 'dev' of https://github.com/SyncrowIOT/syncrow-app into SP-1246 2025-04-03 10:47:27 +04:00
fb867e5df3 updated device endpoint 2025-04-03 10:47:09 +04:00
9472390284 Merge pull request #76 from SyncrowIOT/bugifx/empty-subspace-routine-creation
fixed issue on empty subspace
2025-03-28 11:38:14 +04:00
731ba0f3d6 Merge pull request #77 from SyncrowIOT/SP-1268-FE-Implement-UX-Behavior-for-No-Tab-to-Run-Scene-in-Device-Screen
Sp 1268 fe implement ux behavior for no tab to run scene in device screen
2025-03-26 15:24:34 +03:00
56407c6426 indentation and trailing commas. 2025-03-26 13:49:54 +03:00
02d61ca0bb Refactor DevicesViewBody and SceneView to improve widget structure and replace CreateUnitWidget with EmptyDevicesWidget for better handling of empty states. 2025-03-26 13:44:49 +03:00
99ee4b9878 Add EmptyDevicesWidget to display message when no routines are available. 2025-03-26 13:34:07 +03:00
19edd0a275 Added /android/app/.cxx/ to .gitIgnore, because they're auto generated files that dont need to be checked into source control. 2025-03-26 13:14:23 +03:00
ef5e7c3154 fixed issue on empty subspace 2025-03-25 14:15:14 +04:00
80dd0f696f Merge pull request #75 from SyncrowIOT/SP-1245
updated endpoint for automation
2025-03-17 09:34:46 +04:00
a64a41548f updated delete endpoint for automation 2025-03-14 13:02:14 +04:00
0d50aa68fa updated endpoint for update automation 2025-03-14 12:58:12 +04:00
88aac86b10 updated endpoint for getting automation by id 2025-03-14 12:55:33 +04:00
0673548745 changed endpoint for getting automations by space 2025-03-14 12:53:29 +04:00
c2fc8fa0ae changed endpoint for create automation endpoint 2025-03-14 12:40:52 +04:00
cbf10bbf78 Merge pull request #74 from SyncrowIOT/real_time_app
Real time app
2025-03-03 17:34:34 +03:00
d95588ce84 remove unused code 2025-03-03 17:34:15 +03:00
7e2e591d71 remove unused code 2025-03-01 15:19:15 +03:00
2ec81bda9c connect the real time for all devices 2025-03-01 15:08:51 +03:00
3b0f51473c Merge pull request #73 from SyncrowIOT/SP-1190
Sp 1190
2025-02-26 12:20:06 +03:00
13757d89ee Merged with dev 2025-02-26 12:17:57 +03:00
d3068b8e14 changes in threeGang 2025-02-26 10:58:32 +03:00
7c5d7e1dda remove unused code 2025-02-25 12:45:23 +03:00
0a97a4867d disconnect real-time to some devices 2025-02-25 12:41:49 +03:00
6e55b488aa Merge pull request #72 from SyncrowIOT/feat/change-hardcode-projectid
updated project hardcoded values
2025-02-24 12:06:06 +03:00
22789234fe Sensitivity Start from 1 2025-02-23 16:30:50 +03:00
8393ec353a fetchDevices by projectUuid 2025-02-20 16:02:25 +03:00
0b45d61b25 Fixed list issue in the manage home screen 2025-02-20 10:50:47 +03:00
450b773921 set default values in the devices models instead of late, and fixed issues in the AC bloc 2025-02-20 04:13:37 +03:00
3f7f7ce49f updated project hardcoded values 2025-02-16 20:55:13 +04:00
2dc4e16a75 connect all devices to real-time and change the channel function 2025-02-16 14:54:39 +03:00
cd41720244 active the implemented device 2025-02-16 10:04:34 +03:00
67209961b4 added project model 2025-02-15 11:54:02 +04:00
9098276223 Merge pull request #71 from SyncrowIOT/fixes_bugs_sprint15
fixes bugs and add project id staging
2025-02-12 12:47:09 +03:00
36dfe2c85e change the key 2025-02-12 12:06:00 +03:00
efed5f55a7 add project id to env file and hide about 2025-02-11 11:05:13 +03:00
9897c19dad fixes bugs and add project id staging 2025-02-10 10:26:02 +03:00
48733fd65e Merge pull request #70 from SyncrowIOT/sprint_14_changes
Sprint 14 changes
2025-02-02 22:33:28 +03:00
4ca4086bd3 Merged with dev 2025-02-02 22:32:15 +03:00
4da1b16b18 Merge pull request #69 from SyncrowIOT/role_permission_restrict_user
restrict_spaceMemberUser_and_change_SignUpModel
2025-02-02 14:27:31 +03:00
1189b52c57 remove comment DevicesViewBody and fix home page 2025-02-02 13:17:25 +03:00
c578d63134 all_devices and Restrict_user 2025-01-29 14:10:38 +03:00
457b7c2c51 Updated gradle and kotlin 2025-01-26 20:38:37 +03:00
4ae04cf2af Merged with Dev 2025-01-26 13:08:40 +03:00
d72253e3de hide SceneSettings 2025-01-23 18:41:50 +03:00
790479effb restrict_spaceMemberUser_and_change_SignUpModel 2025-01-23 18:35:01 +03:00
827585815b Merge pull request #68 from SyncrowIOT/user_agreement_policy
User agreement and policy
2025-01-21 12:05:25 +03:00
de024994c9 showSpaceBottomSheet in a DefaultAppBar and Routine trigger from the device screen
and fixes github comments
and i used this package flutter_html: ^3.0.0-beta.2
2025-01-20 15:50:36 +03:00
bcc4ba98ff size changes 2025-01-19 16:56:42 +03:00
df0f1c6c94 user_agreement and privacy_policy sign up and menu 2025-01-19 16:49:54 +03:00
1f62cadcec Merge pull request #66 from SyncrowIOT/Implement_Change_Password_Flow
change_password
2025-01-16 18:02:33 +03:00
f960a553ca Updated the pacakages 2025-01-13 13:02:51 +03:00
90812f78e8 Completed wall sensor implementation 2025-01-12 00:12:08 +03:00
b1368bf4d7 update ios packages 2025-01-12 00:10:02 +03:00
127 changed files with 5740 additions and 2445 deletions

View File

@ -1,2 +1,3 @@
ENV_NAME=development ENV_NAME=development
BASE_URL=https://syncrow-dev.azurewebsites.net BASE_URL=https://syncrow-dev.azurewebsites.net
PROJECT_ID=0e62577c-06fa-41b9-8a92-99a21fbaf51c

View File

@ -1,2 +1,3 @@
ENV_NAME=production ENV_NAME=production
BASE_URL=https://syncrow-staging.azurewebsites.net BASE_URL=https://syncrow-staging.azurewebsites.net
PROJECT_ID=bcda711e-9fc2-4168-a05e-171b4026d1ff

View File

@ -1,2 +1,3 @@
ENV_NAME=staging ENV_NAME=staging
BASE_URL=https://syncrow-staging.azurewebsites.net BASE_URL=https://syncrow-staging.azurewebsites.net
PROJECT_ID=bcda711e-9fc2-4168-a05e-171b4026d1ff

3
.gitignore vendored
View File

@ -5,9 +5,11 @@
*.swp *.swp
.DS_Store .DS_Store
.atom/ .atom/
.build/
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
.swiftpm/
migrate_working_dir/ migrate_working_dir/
# IntelliJ related # IntelliJ related
@ -40,3 +42,4 @@ app.*.map.json
/android/app/debug /android/app/debug
/android/app/profile /android/app/profile
/android/app/release /android/app/release
/android/app/.cxx/

View File

@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.7.10' ext.kotlin_version = '1.9.0'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()

View File

@ -1,3 +1,6 @@
org.gradle.jvmargs=-Xmx4G org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

@ -1,6 +1,6 @@
#Wed Apr 03 23:37:40 EET 2024 #Wed Apr 03 23:37:40 EET 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -23,7 +23,7 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false id "com.android.application" version '8.3.0' apply false
// START: FlutterFire Configuration // START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.3.15" apply false id "com.google.gms.google-services" version "4.3.15" apply false
id "com.google.firebase.crashlytics" version "2.8.1" apply false id "com.google.firebase.crashlytics" version "2.8.1" apply false

View File

@ -0,0 +1,18 @@
<svg width="47" height="37" viewBox="0 0 47 37" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="6" y="1" width="41" height="25" rx="12.5" fill="#E9E9E9"/>
<g filter="url(#filter0_d_6419_4507)">
<circle cx="18.5" cy="13.5" r="10.5" fill="white"/>
</g>
<defs>
<filter id="filter0_d_6419_4507" x="0" y="0" width="37" height="37" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="5"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6419_4507"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6419_4507" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 965 B

View File

@ -0,0 +1,18 @@
<svg width="47" height="37" viewBox="0 0 47 37" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="1" width="41" height="25" rx="12.5" fill="#023DFE" fill-opacity="0.7"/>
<g filter="url(#filter0_d_6689_981)">
<circle cx="28.5" cy="13.5" r="10.5" fill="white"/>
</g>
<defs>
<filter id="filter0_d_6689_981" x="10" y="0" width="37" height="37" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="5"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6689_981"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6689_981" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 975 B

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '12.0' platform :ios, '15.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@ -1,155 +1,153 @@
PODS: PODS:
- device_info_plus (0.0.1): - device_info_plus (0.0.1):
- Flutter - Flutter
- Firebase/Analytics (10.25.0): - Firebase/Analytics (11.6.0):
- Firebase/Core - Firebase/Core
- Firebase/Core (10.25.0): - Firebase/Core (11.6.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseAnalytics (~> 10.25.0) - FirebaseAnalytics (~> 11.6.0)
- Firebase/CoreOnly (10.25.0): - Firebase/CoreOnly (11.6.0):
- FirebaseCore (= 10.25.0) - FirebaseCore (~> 11.6.0)
- Firebase/Crashlytics (10.25.0): - Firebase/Crashlytics (11.6.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseCrashlytics (~> 10.25.0) - FirebaseCrashlytics (~> 11.6.0)
- Firebase/Database (10.25.0): - Firebase/Database (11.6.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseDatabase (~> 10.25.0) - FirebaseDatabase (~> 11.6.0)
- firebase_analytics (10.8.7): - firebase_analytics (11.4.0):
- Firebase/Analytics (= 10.25.0) - Firebase/Analytics (= 11.6.0)
- firebase_core - firebase_core
- Flutter - Flutter
- firebase_core (2.32.0): - firebase_core (3.10.0):
- Firebase/CoreOnly (= 10.25.0) - Firebase/CoreOnly (= 11.6.0)
- Flutter - Flutter
- firebase_crashlytics (3.4.16): - firebase_crashlytics (4.3.0):
- Firebase/Crashlytics (= 10.25.0) - Firebase/Crashlytics (= 11.6.0)
- firebase_core - firebase_core
- Flutter - Flutter
- firebase_database (10.5.7): - firebase_database (11.3.0):
- Firebase/Database (= 10.25.0) - Firebase/Database (= 11.6.0)
- firebase_core - firebase_core
- Flutter - Flutter
- FirebaseAnalytics (10.25.0): - FirebaseAnalytics (11.6.0):
- FirebaseAnalytics/AdIdSupport (= 10.25.0) - FirebaseAnalytics/AdIdSupport (= 11.6.0)
- FirebaseCore (~> 10.0) - FirebaseCore (~> 11.6.0)
- FirebaseInstallations (~> 10.0) - FirebaseInstallations (~> 11.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 7.11) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 7.11)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (< 2.30911.0, >= 2.30908.0) - nanopb (~> 3.30910.0)
- FirebaseAnalytics/AdIdSupport (10.25.0): - FirebaseAnalytics/AdIdSupport (11.6.0):
- FirebaseCore (~> 10.0) - FirebaseCore (~> 11.6.0)
- FirebaseInstallations (~> 10.0) - FirebaseInstallations (~> 11.0)
- GoogleAppMeasurement (= 10.25.0) - GoogleAppMeasurement (= 11.6.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 7.11) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 7.11)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (< 2.30911.0, >= 2.30908.0) - nanopb (~> 3.30910.0)
- FirebaseAppCheckInterop (10.29.0) - FirebaseAppCheckInterop (11.6.0)
- FirebaseCore (10.25.0): - FirebaseCore (11.6.0):
- FirebaseCoreInternal (~> 10.0) - FirebaseCoreInternal (~> 11.6.0)
- GoogleUtilities/Environment (~> 7.12) - GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/Logger (~> 7.12) - GoogleUtilities/Logger (~> 8.0)
- FirebaseCoreExtension (10.29.0): - FirebaseCoreExtension (11.6.0):
- FirebaseCore (~> 10.0) - FirebaseCore (~> 11.6.0)
- FirebaseCoreInternal (10.29.0): - FirebaseCoreInternal (11.6.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- FirebaseCrashlytics (10.25.0): - FirebaseCrashlytics (11.6.0):
- FirebaseCore (~> 10.5) - FirebaseCore (~> 11.6.0)
- FirebaseInstallations (~> 10.0) - FirebaseInstallations (~> 11.0)
- FirebaseRemoteConfigInterop (~> 10.23) - FirebaseRemoteConfigInterop (~> 11.0)
- FirebaseSessions (~> 10.5) - FirebaseSessions (~> 11.0)
- GoogleDataTransport (~> 9.2) - GoogleDataTransport (~> 10.0)
- GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/Environment (~> 8.0)
- nanopb (< 2.30911.0, >= 2.30908.0) - nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.1) - PromisesObjC (~> 2.4)
- FirebaseDatabase (10.25.0): - FirebaseDatabase (11.6.0):
- FirebaseAppCheckInterop (~> 10.17) - FirebaseAppCheckInterop (~> 11.0)
- FirebaseCore (~> 10.0) - FirebaseCore (~> 11.6.0)
- FirebaseSharedSwift (~> 10.0) - FirebaseSharedSwift (~> 11.0)
- GoogleUtilities/UserDefaults (~> 7.13) - GoogleUtilities/UserDefaults (~> 8.0)
- leveldb-library (~> 1.22) - leveldb-library (~> 1.22)
- FirebaseInstallations (10.29.0): - FirebaseInstallations (11.6.0):
- FirebaseCore (~> 10.0) - FirebaseCore (~> 11.6.0)
- GoogleUtilities/Environment (~> 7.8) - GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 7.8) - GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.1) - PromisesObjC (~> 2.4)
- FirebaseRemoteConfigInterop (10.29.0) - FirebaseRemoteConfigInterop (11.6.0)
- FirebaseSessions (10.29.0): - FirebaseSessions (11.6.0):
- FirebaseCore (~> 10.5) - FirebaseCore (~> 11.6.0)
- FirebaseCoreExtension (~> 10.0) - FirebaseCoreExtension (~> 11.6.0)
- FirebaseInstallations (~> 10.0) - FirebaseInstallations (~> 11.0)
- GoogleDataTransport (~> 9.2) - GoogleDataTransport (~> 10.0)
- GoogleUtilities/Environment (~> 7.13) - GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 7.13) - GoogleUtilities/UserDefaults (~> 8.0)
- nanopb (< 2.30911.0, >= 2.30908.0) - nanopb (~> 3.30910.0)
- PromisesSwift (~> 2.1) - PromisesSwift (~> 2.1)
- FirebaseSharedSwift (10.29.0) - FirebaseSharedSwift (11.6.0)
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_secure_storage (6.0.0): - flutter_secure_storage (6.0.0):
- Flutter - Flutter
- GoogleAppMeasurement (10.25.0): - GoogleAppMeasurement (11.6.0):
- GoogleAppMeasurement/AdIdSupport (= 10.25.0) - GoogleAppMeasurement/AdIdSupport (= 11.6.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 7.11) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 7.11)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (< 2.30911.0, >= 2.30908.0) - nanopb (~> 3.30910.0)
- GoogleAppMeasurement/AdIdSupport (10.25.0): - GoogleAppMeasurement/AdIdSupport (11.6.0):
- GoogleAppMeasurement/WithoutAdIdSupport (= 10.25.0) - GoogleAppMeasurement/WithoutAdIdSupport (= 11.6.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 7.11) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 7.11)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (< 2.30911.0, >= 2.30908.0) - nanopb (~> 3.30910.0)
- GoogleAppMeasurement/WithoutAdIdSupport (10.25.0): - GoogleAppMeasurement/WithoutAdIdSupport (11.6.0):
- GoogleUtilities/AppDelegateSwizzler (~> 7.11) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 7.11) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 7.11) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 7.11)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (< 2.30911.0, >= 2.30908.0) - nanopb (~> 3.30910.0)
- GoogleDataTransport (9.4.1): - GoogleDataTransport (10.1.0):
- GoogleUtilities/Environment (~> 7.7) - nanopb (~> 3.30910.0)
- nanopb (< 2.30911.0, >= 2.30908.0) - PromisesObjC (~> 2.4)
- PromisesObjC (< 3.0, >= 1.2) - GoogleUtilities/AppDelegateSwizzler (8.0.2):
- GoogleUtilities/AppDelegateSwizzler (7.13.3):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Network - GoogleUtilities/Network
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- GoogleUtilities/Environment (7.13.3): - GoogleUtilities/Environment (8.0.2):
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- PromisesObjC (< 3.0, >= 1.2) - GoogleUtilities/Logger (8.0.2):
- GoogleUtilities/Logger (7.13.3):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- GoogleUtilities/MethodSwizzler (7.13.3): - GoogleUtilities/MethodSwizzler (8.0.2):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- GoogleUtilities/Network (7.13.3): - GoogleUtilities/Network (8.0.2):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib" - "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- GoogleUtilities/Reachability - GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.13.3)": - "GoogleUtilities/NSData+zlib (8.0.2)":
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- GoogleUtilities/Privacy (7.13.3) - GoogleUtilities/Privacy (8.0.2)
- GoogleUtilities/Reachability (7.13.3): - GoogleUtilities/Reachability (8.0.2):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- GoogleUtilities/UserDefaults (7.13.3): - GoogleUtilities/UserDefaults (8.0.2):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- image_picker_ios (0.0.1): - image_picker_ios (0.0.1):
- Flutter - Flutter
- leveldb-library (1.22.5) - leveldb-library (1.22.6)
- nanopb (2.30910.0): - nanopb (3.30910.0):
- nanopb/decode (= 2.30910.0) - nanopb/decode (= 3.30910.0)
- nanopb/encode (= 2.30910.0) - nanopb/encode (= 3.30910.0)
- nanopb/decode (2.30910.0) - nanopb/decode (3.30910.0)
- nanopb/encode (2.30910.0) - nanopb/encode (3.30910.0)
- onesignal_flutter (5.2.0): - onesignal_flutter (5.2.0):
- Flutter - Flutter
- OneSignalXCFramework (= 5.2.0) - OneSignalXCFramework (= 5.2.0)
@ -291,42 +289,42 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_ios/ios" :path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
Firebase: 0312a2352584f782ea56f66d91606891d4607f06 Firebase: 374a441a91ead896215703a674d58cdb3e9d772b
firebase_analytics: 3a9263fedec72970e6bd30a7132bbdd386de2c14 firebase_analytics: 07bd7cfbac54bfcdccf2bb2530f9a65486f7ef3f
firebase_core: a626d00494efa398e7c54f25f1454a64c8abf197 firebase_core: feb37e79f775c2bd08dd35e02d83678291317e10
firebase_crashlytics: 0b7cb41f5fb3b6889d0fb408cfce3cc7a4247061 firebase_crashlytics: 609a5f6f4a2f5af9e40a68182e0c1be3ca2a02f6
firebase_database: 2713033e426b176d4fe5e7195f3d19aa1b549a91 firebase_database: adc9efd0b70cdc8d1e6f3c9f6bb054a625c4f45d
FirebaseAnalytics: ec00fe8b93b41dc6fe4a28784b8e51da0647a248 FirebaseAnalytics: 7114c698cac995602e3b1b96663473e50d54d6e7
FirebaseAppCheckInterop: 6a1757cfd4067d8e00fccd14fcc1b8fd78cfac07 FirebaseAppCheckInterop: 347aa09a805219a31249b58fc956888e9fcb314b
FirebaseCore: 7ec4d0484817f12c3373955bc87762d96842d483 FirebaseCore: 48b0dd707581cf9c1a1220da68223fb0a562afaa
FirebaseCoreExtension: 705ca5b14bf71d2564a0ddc677df1fc86ffa600f FirebaseCoreExtension: 2d77d6430c16cf43ca2b04608302ed02b3598361
FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934 FirebaseCoreInternal: d98ab91e2d80a56d7b246856a8885443b302c0c2
FirebaseCrashlytics: 4b96efb0ce73b38b2a85e8b8bd1bd8f63f09d015 FirebaseCrashlytics: b21c665fb50138766480bce73ebdb1aa30f7f300
FirebaseDatabase: faa489a42f5f868d23a55dd442d6e2099348458e FirebaseDatabase: ce3a83a39ab50559a85c5add54f6f285544433b8
FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd FirebaseInstallations: efc0946fc756e4d22d8113f7c761948120322e8c
FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d FirebaseRemoteConfigInterop: e75e348953352a000331eb77caf01e424248e176
FirebaseSessions: dbd14adac65ce996228652c1fc3a3f576bdf3ecc FirebaseSessions: 9529d14180868e29a8da164b3a729c036204918b
FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e FirebaseSharedSwift: a4e5dfca3e210633bb3a3dfb94176c019211948b
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
GoogleAppMeasurement: 9abf64b682732fed36da827aa2a68f0221fd2356 GoogleAppMeasurement: 6a9e6317b6a6d810ad03d4a66564ca6c4c5818a3
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
leveldb-library: e8eadf9008a61f9e1dde3978c086d2b6d9b9dc28 leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19
nanopb: 438bc412db1928dac798aa6fd75726007be04262 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
onesignal_flutter: 5ce68a29861960168e81101cb1bd685d264361de onesignal_flutter: 5ce68a29861960168e81101cb1bd685d264361de
OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095 OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: 4243bd7f9184f79552dd731a7c9d5cad03bd2706 PODFILE CHECKSUM: deba6d843ff3cf709e6e9051ce6601a587b24105
COCOAPODS: 1.15.2 COCOAPODS: 1.16.2

View File

@ -547,6 +547,7 @@
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow; INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -739,6 +740,7 @@
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow; INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -769,6 +771,7 @@
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow; INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -856,6 +859,7 @@
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow; INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -959,6 +963,7 @@
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow; INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1057,6 +1062,7 @@
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Syncrow; INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",

View File

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

View File

@ -38,5 +38,10 @@
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
</array> </array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sms</string>
<string>tel</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -7,10 +7,11 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart'; import 'package:onesignal_flutter/onesignal_flutter.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:syncrow_app/features/app_layout/model/permission_model.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart'; import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart'; 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/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/subspace_model.dart'; import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart'; import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
@ -28,25 +29,33 @@ import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/devices_api.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/profile_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.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/color_manager.dart';
part 'home_state.dart'; part 'home_state.dart';
class HomeCubit extends Cubit<HomeState> { class HomeCubit extends Cubit<HomeState> {
HomeCubit._() : super(HomeInitial()) { HomeCubit._() : super(HomeInitial()) {
// checkIfNotificationPermissionGranted(); // checkIfNotificationPermissionGranted();
fetchUserInfo(); fetchUserInfo().then(
if (selectedSpace == null) { (value) {
fetchUnitsByUserId(); if (selectedSpace == null) {
// .then((value) { fetchUnitsByUserId();
// if (selectedSpace != null) { fetchPermissions();
// fetchRoomsByUnitId(selectedSpace!);
// } // .then((value) {
// }); // if (selectedSpace != null) {
} // fetchRoomsByUnitId(selectedSpace!);
// }
// });
}
},
);
} }
static UserModel? user; static UserModel? user;
List<PermissionModel>? permissionModel = [];
static HomeCubit? _instance; static HomeCubit? _instance;
static HomeCubit getInstance() { static HomeCubit getInstance() {
// If an instance already exists, return it // If an instance already exists, return it
@ -56,15 +65,90 @@ class HomeCubit extends Cubit<HomeState> {
Future fetchUserInfo() async { Future fetchUserInfo() async {
try { try {
emit(HomeLoading());
var uuid = var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey); await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await ProfileApi().fetchUserInfo(uuid); user = await ProfileApi().fetchUserInfo(uuid);
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info project = user?.project;
emit(HomeUserInfoLoaded(user!));
} catch (e) { } catch (e) {
return; return;
} }
} }
static bool manageSupSpace = false;
static bool manageScene = false;
static bool manageDeviceLocation = false;
static bool visitorPasswordManagement = false;
String errorMsg = '';
Future<void> fetchPermissions() async {
try {
emit(HomeLoading());
final response = await ProfileApi().fetchPermissions(user!.role!.uuid);
permissionModel = PermissionModel.fromJsonList(response);
hasViewPermission();
emit(PermissionsRoleLoaded(permissionModel!));
} catch (e) {
emit(HomeError(e.toString()));
}
}
void hasViewPermission() {
emit(HomeLoading());
manageSupSpace = hasPermission(
permissionModel!,
'SPACE_MANAGEMENT',
'MANAGE_SPACE',
'ASSIGN_USER_TO_SPACE',
);
manageScene = hasPermission(
permissionModel!,
'AUTOMATION_MANAGEMENT',
'MANAGE_SCENES',
'UPDATE',
);
manageDeviceLocation = hasPermission(
permissionModel!,
'DEVICE_MANAGEMENT',
'MANAGE_DEVICE',
'LOCATION_UPDATE',
);
visitorPasswordManagement = hasPermission(
permissionModel!,
'VISITOR_PASSWORD_MANAGEMENT',
'MANAGE_VISITOR_PASSWORD',
'VIEW',
);
emit(HomePermissionUpdated());
}
bool hasPermission(List<PermissionModel> permissions, String mainTitle,
String subTitle, String finalTitle) {
try {
final mainOption = permissions.firstWhere(
(perm) => perm.title == mainTitle,
);
final subOption = mainOption.subOptions.firstWhere(
(sub) => sub.title == subTitle,
);
if (subOption.subOptions == null) {
return false;
}
final finalOption = subOption.subOptions!.firstWhere(
(finalSub) => finalSub.title == finalTitle,
);
return finalOption.isChecked == true;
} catch (e) {
return false;
}
}
void emitSafe(HomeState newState) { void emitSafe(HomeState newState) {
final cubit = this; final cubit = this;
if (!cubit.isClosed) { if (!cubit.isClosed) {
@ -89,12 +173,14 @@ class HomeCubit extends Cubit<HomeState> {
static HomeCubit get(context) => BlocProvider.of(context); static HomeCubit get(context) => BlocProvider.of(context);
List<SpaceModel>? spaces; List<SpaceModel> spaces = [];
SpaceModel? selectedSpace; SpaceModel? selectedSpace;
SubSpaceModel? selectedRoom; SubSpaceModel? selectedRoom;
Project? project;
PageController devicesPageController = PageController(); PageController devicesPageController = PageController();
PageController roomsPageController = PageController(); PageController roomsPageController = PageController();
@ -182,8 +268,10 @@ class HomeCubit extends Cubit<HomeState> {
if (index == 0) { if (index == 0) {
unselectRoom(); unselectRoom();
} else if (index == 1) {
unselectRoom1();
} else { } else {
selectedRoom = selectedSpace!.subspaces[index - 1]; selectedRoom = selectedSpace!.subspaces[index - 2];
emitSafe(RoomSelected(selectedRoom!)); emitSafe(RoomSelected(selectedRoom!));
} }
} }
@ -197,8 +285,10 @@ class HomeCubit extends Cubit<HomeState> {
if (index <= 0) { if (index <= 0) {
unselectRoom(); unselectRoom();
} else if (index == 1) {
unselectRoom1();
} else { } else {
selectedRoom = selectedSpace!.subspaces[index - 1]; selectedRoom = selectedSpace!.subspaces[index - 2];
emitSafe(RoomSelected(selectedRoom!)); emitSafe(RoomSelected(selectedRoom!));
} }
} }
@ -220,11 +310,28 @@ class HomeCubit extends Cubit<HomeState> {
emitSafe(RoomUnSelected()); emitSafe(RoomUnSelected());
} }
unselectRoom1() {
// selectedRoom = null;
devicesPageController.animateToPage(
1,
duration: duration,
curve: Curves.linear,
);
roomsPageController.animateToPage(
1,
duration: duration,
curve: Curves.linear,
);
emitSafe(RoomUnSelected());
}
//////////////////////////////////////// API //////////////////////////////////////// //////////////////////////////////////// API ////////////////////////////////////////
generateInvitation(SpaceModel unit) async { generateInvitation(SpaceModel unit) async {
try { try {
final invitationCode = final invitationCode = await SpacesAPI.generateInvitationCode(unit.id,
await SpacesAPI.generateInvitationCode(unit.id, unit.community.uuid); unit.community.uuid, project?.uuid ?? TempConst.projectIdDev);
if (invitationCode.isNotEmpty) { if (invitationCode.isNotEmpty) {
Share.share('The invitation code is $invitationCode'); Share.share('The invitation code is $invitationCode');
CustomSnackBar.displaySnackBar( CustomSnackBar.displaySnackBar(
@ -261,15 +368,16 @@ class HomeCubit extends Cubit<HomeState> {
emitSafe(GetSpacesLoading()); emitSafe(GetSpacesLoading());
try { try {
spaces = await SpacesAPI.getSpacesByUserId(); spaces = await SpacesAPI.getSpacesByUserId();
emitSafe(GetSpacesSuccess(spaces));
} catch (failure) { } catch (failure) {
emitSafe(GetSpacesError("No units found")); emitSafe(GetSpacesError("No units found"));
return; return;
} }
if (spaces != null && spaces!.isNotEmpty) { if (spaces.isNotEmpty) {
selectedSpace = spaces!.first; selectedSpace = spaces.first;
await fetchRoomsByUnitId(selectedSpace!); await fetchRoomsByUnitId(selectedSpace!);
emitSafe(GetSpacesSuccess(spaces!)); emitSafe(GetSpacesSuccess(spaces));
} else { } else {
emitSafe(GetSpacesError("No spaces found")); emitSafe(GetSpacesError("No spaces found"));
} }
@ -278,8 +386,10 @@ class HomeCubit extends Cubit<HomeState> {
fetchRoomsByUnitId(SpaceModel space) async { fetchRoomsByUnitId(SpaceModel space) async {
emitSafe(GetSpaceRoomsLoading()); emitSafe(GetSpaceRoomsLoading());
try { try {
space.subspaces = space.subspaces = await SpacesAPI.getSubSpaceBySpaceId(
await SpacesAPI.getSubSpaceBySpaceId(space.community.uuid, space.id); space.community.uuid,
space.id,
project?.uuid ?? TempConst.projectIdDev);
} catch (failure) { } catch (failure) {
emitSafe(GetSpaceRoomsError(failure.toString())); emitSafe(GetSpaceRoomsError(failure.toString()));
return; return;
@ -298,18 +408,18 @@ class HomeCubit extends Cubit<HomeState> {
await const FlutterSecureStorage().read(key: UserModel.userUuidKey); await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
var res = await SpacesAPI.activationCodeSpace( var res = await SpacesAPI.activationCodeSpace(
activationCode: activationCode, userUuid: uuid); activationCode: activationCode, userUuid: uuid);
if (res['success'] == true) { if (res['success'] == true) {
fetchUserInfo(); fetchUserInfo();
fetchUnitsByUserId(); fetchUnitsByUserId();
} }
emitSafe(GetSpacesSuccess(spaces!)); emitSafe(GetSpacesSuccess(spaces!));
return res['success']; return res['success'];
} on DioException catch (e) { } on DioException catch (e) {
final errorMessage = e.response?.data['error']['message']; final errorMessage = e.response?.data['error']['message'];
emitSafe(ActivationError(errMessage: errorMessage)); errorMsg = e.response?.data['error']['message'];
return false; emitSafe(ActivationError(errMessage: errorMsg));
} catch (e) {
emitSafe(ActivationError(errMessage: e.toString()));
return false; return false;
} }
} }
@ -378,42 +488,44 @@ class HomeCubit extends Cubit<HomeState> {
// ), // ),
// onPressed: () {}, // onPressed: () {},
// ), // ),
IconButton( manageScene
icon: const Icon( ? IconButton(
Icons.add, icon: const Icon(
size: 32, Icons.add,
), size: 32,
style: ButtonStyle( ),
foregroundColor: style: ButtonStyle(
WidgetStateProperty.all(ColorsManager.textPrimaryColor), foregroundColor:
), WidgetStateProperty.all(ColorsManager.textPrimaryColor),
onPressed: () { ),
Navigator.pushNamed( onPressed: () {
NavigationService.navigatorKey.currentContext!, Navigator.pushNamed(
Routes.sceneTasksRoute, NavigationService.navigatorKey.currentContext!,
arguments: SceneSettingsRouteArguments( Routes.sceneTasksRoute,
sceneType: '', arguments: SceneSettingsRouteArguments(
sceneId: '', sceneType: '',
sceneName: '', sceneId: '',
), sceneName: '',
); ),
NavigationService.navigatorKey.currentContext! );
.read<CreateSceneBloc>() NavigationService.navigatorKey.currentContext!
.add(const ClearTaskListEvent()); .read<CreateSceneBloc>()
NavigationService.navigatorKey.currentContext! .add(const ClearTaskListEvent());
.read<CreateSceneBloc>() NavigationService.navigatorKey.currentContext!
.add(const SceneTypeEvent(CreateSceneEnum.none)); .read<CreateSceneBloc>()
NavigationService.navigatorKey.currentContext! .add(const SceneTypeEvent(CreateSceneEnum.none));
.read<SmartSceneSelectBloc>() NavigationService.navigatorKey.currentContext!
.add(const SmartSceneClearEvent()); .read<SmartSceneSelectBloc>()
BlocProvider.of<EffectPeriodBloc>( .add(const SmartSceneClearEvent());
NavigationService.navigatorKey.currentState!.context) BlocProvider.of<EffectPeriodBloc>(
.add(ResetEffectivePeriod()); NavigationService.navigatorKey.currentState!.context)
NavigationService.navigatorKey.currentContext! .add(ResetEffectivePeriod());
.read<CreateSceneBloc>() NavigationService.navigatorKey.currentContext!
.add(const ClearTabToRunSetting()); .read<CreateSceneBloc>()
}, .add(const ClearTabToRunSetting());
), },
)
: const SizedBox(),
// IconButton( // IconButton(
// icon: const Icon( // icon: const Icon(
// Icons.more_vert, // Icons.more_vert,
@ -503,3 +615,28 @@ BottomNavigationBarItem defaultBottomNavBarItem(
label: label, label: label,
); );
} }
// class PermissionUtils {
// // Check if the "VIEW" permission exists in "MANAGE_SUBSPACE"
// static bool hasViewPermission(List<dynamic> permissions) {
// return _hasPermission(permissions, 'MANAGE_SUBSPACE', 'VIEW');
// }
// // Generalized permission checker
// static bool _hasPermission(
// List<dynamic> permissions, String mainTitle, String subTitle) {
// final mainOption = permissions.firstWhere(
// (perm) => perm['title'] == mainTitle,
// orElse: () => null,
// );
// if (mainOption != null) {
// final subOption = mainOption['subOptions'].firstWhere(
// (sub) => sub['title'] == subTitle,
// orElse: () => null,
// );
// return subOption != null && subOption['isChecked'] == true;
// }
// return false;
// }
// }

View File

@ -15,8 +15,8 @@ class HomeError extends HomeState {
class HomeSuccess extends HomeState {} class HomeSuccess extends HomeState {}
///specific states class ActivationSuccess extends HomeState {}
//get spaces
class GetSpacesLoading extends HomeLoading {} class GetSpacesLoading extends HomeLoading {}
class GetSpacesSuccess extends HomeSuccess { class GetSpacesSuccess extends HomeSuccess {
@ -65,9 +65,15 @@ class RoomUnSelected extends HomeState {}
class NavChangePage extends HomeState {} class NavChangePage extends HomeState {}
// Define new state classes class HomePermissionUpdated extends HomeState {}
class HomeUserInfoLoaded extends HomeState { class HomeUserInfoLoaded extends HomeState {
final UserModel user; final UserModel user;
HomeUserInfoLoaded(this.user); HomeUserInfoLoaded(this.user);
} }
class PermissionsRoleLoaded extends HomeState {
final List<PermissionModel> permissionModel;
PermissionsRoleLoaded(this.permissionModel);
}

View File

@ -0,0 +1,39 @@
class PermissionModel {
final String title;
final List<PermissionAttributes> subOptions;
PermissionModel({required this.title, required this.subOptions});
factory PermissionModel.fromJson(Map<String, dynamic> json) {
return PermissionModel(
title: json['title'],
subOptions: (json['subOptions'] as List)
.map((e) => PermissionAttributes.fromJson(e))
.toList(),
);
}
static List<PermissionModel> fromJsonList(List<dynamic> jsonList) {
return jsonList.map((json) => PermissionModel.fromJson(json)).toList();
}
}
class PermissionAttributes {
final String title;
final List<PermissionAttributes>? subOptions;
final bool? isChecked;
PermissionAttributes({required this.title, this.subOptions, this.isChecked});
factory PermissionAttributes.fromJson(Map<String, dynamic> json) {
return PermissionAttributes(
title: json['title'],
isChecked: json['isChecked'],
subOptions: json['subOptions'] != null
? (json['subOptions'] as List)
.map((e) => PermissionAttributes.fromJson(e))
.toList()
: null,
);
}
}

View File

@ -17,7 +17,10 @@ class AppLayout extends StatelessWidget {
child: BlocBuilder<HomeCubit, HomeState>( child: BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) { builder: (context, state) {
return DefaultScaffold( return DefaultScaffold(
appBar: HomeCubit.getInstance().spaces != null ? const DefaultAppBar() : null, appBar: HomeCubit.getInstance().spaces != null &&
HomeCubit.getInstance().spaces!.isNotEmpty
? const DefaultAppBar()
: null,
bottomNavBar: const DefaultNavBar(), bottomNavBar: const DefaultNavBar(),
child: const AppBody(), child: const AppBody(),
); );

View File

@ -1,7 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.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/constants.dart';
class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
@ -19,10 +22,23 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
leadingWidth: 200, leadingWidth: 200,
toolbarHeight: Constants.appBarHeight, toolbarHeight: Constants.appBarHeight,
leading: HomeCubit.getInstance().spaces!.isNotEmpty leading: InkWell(
? HomeCubit.appBarLeading[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]! onTap: () {
final spaces = HomeCubit.getInstance().spaces!;
showSpaceBottomSheet(context, spaces);
},
child: HomeCubit.getInstance().spaces!.isNotEmpty
? AbsorbPointer(
absorbing: true,
child: HomeCubit.appBarLeading[HomeCubit
.bottomNavItems[HomeCubit.pageIndex].label]!,
)
: null,
),
actions: HomeCubit.manageScene
? HomeCubit.appBarActions[
HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
: null, : null,
actions: HomeCubit.appBarActions[HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
)); ));
}, },
); );
@ -31,3 +47,83 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
@override @override
Size get preferredSize => Size.fromHeight(Constants.appBarHeight); Size get preferredSize => Size.fromHeight(Constants.appBarHeight);
} }
void showSpaceBottomSheet(BuildContext context, List<SpaceModel> spaces) {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setModalState) {
String? selectedSpaceId = HomeCubit.getInstance().selectedSpace?.id;
final bool shouldLimitHeight = spaces.length > 5;
return Container(
constraints: shouldLimitHeight
? BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.5,
)
: const BoxConstraints(),
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 10),
Container(
decoration: const BoxDecoration(color: Colors.black12),
height: 5,
width: 50,
),
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: spaces.length,
itemBuilder: (BuildContext context, int index) {
final space = spaces[index];
return Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(space.name),
],
),
Radio<String>(
value: space.id,
groupValue: selectedSpaceId,
onChanged: (String? newValue) {
if (newValue != null) {
setModalState(() {
selectedSpaceId = newValue;
});
HomeCubit.getInstance().changeSelectedSpace(
spaces.firstWhere((s) => s.id == newValue),
);
Navigator.of(context).pop();
}
},
),
],
),
);
},
separatorBuilder: (BuildContext context, int index) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: const Divider(
color: Colors.grey,
thickness: 0.5,
),
);
},
),
],
),
),
);
},
);
},
);
}

View File

@ -221,6 +221,7 @@ class AuthCubit extends Cubit<AuthState> {
List<String> userFullName = fullName.split(' '); List<String> userFullName = fullName.split(' ');
response = await AuthenticationAPI.signUp( response = await AuthenticationAPI.signUp(
model: SignUpModel( model: SignUpModel(
hasAcceptedAppAgreement: true,
email: email.toLowerCase(), email: email.toLowerCase(),
password: signUpPassword, password: signUpPassword,
firstName: userFullName[0], firstName: userFullName[0],

View File

@ -0,0 +1,27 @@
class Project {
final String uuid;
final String name;
final String description;
const Project({
required this.uuid,
required this.name,
required this.description,
});
factory Project.fromJson(Map<String, dynamic> json) {
return Project(
uuid: json['uuid'] as String,
name: json['name'] as String,
description: json['description'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'uuid': uuid,
'name': name,
'description': description,
};
}
}

View File

@ -3,10 +3,12 @@ class SignUpModel {
final String password; final String password;
final String firstName; final String firstName;
final String lastName; final String lastName;
final bool hasAcceptedAppAgreement;
SignUpModel( SignUpModel(
{required this.email, {required this.email,
required this.password, required this.password,
required this.hasAcceptedAppAgreement,
required this.firstName, required this.firstName,
required this.lastName}); required this.lastName});
@ -15,7 +17,8 @@ class SignUpModel {
email: json['email'], email: json['email'],
password: json['password'], password: json['password'],
firstName: json['firstName'], firstName: json['firstName'],
lastName: json['lastName']); lastName: json['lastName'],
hasAcceptedAppAgreement: true);
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -24,6 +27,7 @@ class SignUpModel {
'password': password, 'password': password,
'firstName': firstName, 'firstName': firstName,
'lastName': lastName, 'lastName': lastName,
"hasAcceptedAppAgreement": hasAcceptedAppAgreement
}; };
} }
} }

View File

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/auth/model/token.dart'; import 'package:syncrow_app/features/auth/model/token.dart';
class UserModel { class UserModel {
@ -15,6 +16,12 @@ class UserModel {
final String? timeZone; final String? timeZone;
final String? regionUuid; final String? regionUuid;
final bool? isAgreementAccepted; final bool? isAgreementAccepted;
final bool? hasAcceptedWebAgreement;
final DateTime? webAgreementAcceptedAt;
final bool? hasAcceptedAppAgreement;
final DateTime? appAgreementAcceptedAt;
final Role? role;
final Project? project;
UserModel({ UserModel({
required this.uuid, required this.uuid,
@ -28,7 +35,12 @@ class UserModel {
required this.isAgreementAccepted, required this.isAgreementAccepted,
required this.regionName, required this.regionName,
required this.timeZone, required this.timeZone,
// required this.role, required this.hasAcceptedWebAgreement,
required this.webAgreementAcceptedAt,
required this.hasAcceptedAppAgreement,
required this.appAgreementAcceptedAt,
required this.role,
required this.project,
}); });
factory UserModel.fromJson(Map<String, dynamic> json) { factory UserModel.fromJson(Map<String, dynamic> json) {
@ -44,24 +56,44 @@ class UserModel {
regionName: json['region']?['regionName'], regionName: json['region']?['regionName'],
timeZone: json['timeZone']?['timeZoneOffset'], timeZone: json['timeZone']?['timeZoneOffset'],
regionUuid: json['region']?['uuid'], regionUuid: json['region']?['uuid'],
hasAcceptedWebAgreement: json['hasAcceptedWebAgreement'],
webAgreementAcceptedAt: json['webAgreementAcceptedAt'] != null
? DateTime.parse(json['webAgreementAcceptedAt'])
: null,
hasAcceptedAppAgreement: json['hasAcceptedAppAgreement'],
appAgreementAcceptedAt: json['appAgreementAcceptedAt'] != null
? DateTime.parse(json['appAgreementAcceptedAt'])
: null,
role: json['role'] != null ? Role.fromJson(json['role']) : null,
project:
json['project'] != null ? Project.fromJson(json['project']) : null,
); );
} }
factory UserModel.fromToken(Token token) { factory UserModel.fromToken(Token token) {
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken); Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
return UserModel( return UserModel(
uuid: tempJson['uuid'].toString(), uuid: tempJson['uuid'].toString(),
email: tempJson['email'], email: tempJson['email'],
lastName: tempJson['lastName'], lastName: tempJson['lastName'],
firstName: tempJson['firstName'], firstName: tempJson['firstName'],
profilePicture: UserModel.decodeBase64Image(tempJson['profilePicture']), profilePicture: UserModel.decodeBase64Image(tempJson['profilePicture']),
phoneNumber: null, phoneNumber: null,
isEmailVerified: null, isEmailVerified: null,
isAgreementAccepted: null, isAgreementAccepted: null,
regionUuid: null, regionUuid: null,
regionName: tempJson['region']?['regionName'], regionName: tempJson['region']?['regionName'],
timeZone: tempJson['timezone']?['timeZoneOffset'], timeZone: tempJson['timezone']?['timeZoneOffset'],
); hasAcceptedWebAgreement: tempJson['hasAcceptedWebAgreement'],
webAgreementAcceptedAt: tempJson['webAgreementAcceptedAt'] != null
? DateTime.parse(tempJson['webAgreementAcceptedAt'])
: null,
hasAcceptedAppAgreement: tempJson['hasAcceptedAppAgreement'],
appAgreementAcceptedAt: tempJson['appAgreementAcceptedAt'] != null
? DateTime.parse(tempJson['appAgreementAcceptedAt'])
: null,
role: tempJson['role'] != null ? Role.fromJson(tempJson['role']) : null,
project: null);
} }
static Uint8List? decodeBase64Image(String? base64String) { static Uint8List? decodeBase64Image(String? base64String) {
@ -85,6 +117,45 @@ class UserModel {
'isAgreementAccepted': isAgreementAccepted, 'isAgreementAccepted': isAgreementAccepted,
'regionName': regionName, 'regionName': regionName,
'timeZone': timeZone, 'timeZone': timeZone,
'hasAcceptedWebAgreement': hasAcceptedWebAgreement,
'webAgreementAcceptedAt': webAgreementAcceptedAt?.toIso8601String(),
'hasAcceptedAppAgreement': hasAcceptedAppAgreement,
'appAgreementAcceptedAt': appAgreementAcceptedAt?.toIso8601String(),
'role': role?.toJson(),
};
}
}
class Role {
final String? uuid;
final DateTime? createdAt;
final DateTime? updatedAt;
final String? type;
Role({
required this.uuid,
required this.createdAt,
required this.updatedAt,
required this.type,
});
factory Role.fromJson(Map<String, dynamic> json) {
return Role(
uuid: json['uuid'],
createdAt:
json['createdAt'] != null ? DateTime.parse(json['createdAt']) : null,
updatedAt:
json['updatedAt'] != null ? DateTime.parse(json['updatedAt']) : null,
type: json['type'],
);
}
Map<String, dynamic> toJson() {
return {
'uuid': uuid,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'type': type,
}; };
} }
} }

View File

@ -3,12 +3,15 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/features/menu/bloc/privacy_policy.dart';
import 'package:syncrow_app/features/menu/bloc/user_agreement.dart';
import 'package:syncrow_app/features/shared_widgets/default_button.dart'; import 'package:syncrow_app/features/shared_widgets/default_button.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
import 'package:syncrow_app/utils/resource_manager/styles_manager.dart'; import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
@ -202,6 +205,93 @@ class SignUpView extends StatelessWidget {
hint: "At least 8 characters"), hint: "At least 8 characters"),
), ),
const SizedBox(height: 40), const SizedBox(height: 40),
Center(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0),
child: Text.rich(
TextSpan(
text:
'By signing up you agree to our ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontSize: 16,
color: ColorsManager
.onPrimaryColor,
),
children: [
WidgetSpan(
child: GestureDetector(
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) =>
const UserAgreement(),
));
},
child: BodyMedium(
text: 'Terms & Conditions',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(
decoration:
TextDecoration
.underline,
decorationColor:
ColorsManager
.onPrimaryColor,
color: ColorsManager
.onPrimaryColor,
fontSize: 16),
),
),
),
TextSpan(
text: ' and ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontSize: 16,
color: ColorsManager
.onPrimaryColor,
)),
WidgetSpan(
child: GestureDetector(
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) =>
const PrivacyPolicy(),
));
},
child: BodyMedium(
text: 'Privacy Policy',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(
decoration:
TextDecoration
.underline,
decorationColor:
Colors.white,
color: ColorsManager
.onPrimaryColor,
fontSize: 16),
),
),
),
],
),
textAlign: TextAlign.center,
),
),
),
const SizedBox(height: 40),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [

View File

@ -0,0 +1,19 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class ProjectCubit extends Cubit<String?> {
final FlutterSecureStorage storage;
static const String projectKey = "selected_project_uuid";
ProjectCubit(this.storage) : super(null);
Future<void> setProjectUUID(String newUUID) async {
await storage.write(key: projectKey, value: newUUID);
emit(newUUID);
}
Future<void> clearProjectUUID() async {
await storage.delete(key: projectKey);
emit(null);
}
}

View File

@ -7,7 +7,7 @@ import 'package:syncrow_app/features/shared_widgets/create_unit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
import 'widgets/energy_usage.dart'; // import 'widgets/energy_usage.dart';
class DashboardView extends StatelessWidget { class DashboardView extends StatelessWidget {
const DashboardView({super.key}); const DashboardView({super.key});
@ -29,7 +29,7 @@ class DashboardView extends StatelessWidget {
), ),
const LiveMonitorTab(), const LiveMonitorTab(),
const SizedBox(height: 10), const SizedBox(height: 10),
const EnergyUsage(), // const EnergyUsage(),
Container( Container(
padding: const EdgeInsets.only(top: 20), padding: const EdgeInsets.only(top: 20),
constraints: const BoxConstraints( constraints: const BoxConstraints(

View File

@ -1,178 +1,178 @@
import 'package:fl_chart/fl_chart.dart'; // import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; // import 'package:flutter/material.dart';
import 'package:syncrow_app/features/dashboard/view/widgets/energy_usage_header.dart'; // import 'package:syncrow_app/features/dashboard/view/widgets/energy_usage_header.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; // import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; // import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class EnergyUsage extends StatelessWidget { // class EnergyUsage extends StatelessWidget {
const EnergyUsage({ // const EnergyUsage({
super.key, // super.key,
}); // });
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return DecoratedBox( // return DecoratedBox(
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.white, // color: Colors.white,
borderRadius: BorderRadius.circular(15), // borderRadius: BorderRadius.circular(15),
), // ),
child: Padding( // child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), // padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column( // child: Column(
mainAxisAlignment: MainAxisAlignment.start, // mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
const EnergyUsageHeader(), // const EnergyUsageHeader(),
ConstrainedBox( // ConstrainedBox(
constraints: const BoxConstraints( // constraints: const BoxConstraints(
maxHeight: 150, // maxHeight: 150,
minHeight: 150, // minHeight: 150,
), // ),
child: LineChart( // child: LineChart(
LineChartData( // LineChartData(
gridData: FlGridData( // gridData: FlGridData(
show: true, // show: true,
drawHorizontalLine: true, // drawHorizontalLine: true,
horizontalInterval: 2, // horizontalInterval: 2,
drawVerticalLine: false, // drawVerticalLine: false,
getDrawingHorizontalLine: (value) { // getDrawingHorizontalLine: (value) {
return FlLine( // return FlLine(
color: Colors.grey.withOpacity(.5), // color: Colors.grey.withOpacity(.5),
strokeWidth: 1, // strokeWidth: 1,
); // );
}, // },
), // ),
titlesData: FlTitlesData( // titlesData: FlTitlesData(
show: true, // show: true,
rightTitles: AxisTitles( // rightTitles: AxisTitles(
sideTitles: SideTitles( // sideTitles: SideTitles(
showTitles: true, // showTitles: true,
interval: 1, // interval: 1,
getTitlesWidget: leftTitleWidgets, // getTitlesWidget: leftTitleWidgets,
reservedSize: 25, // reservedSize: 25,
), // ),
), // ),
topTitles: const AxisTitles( // topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false), // sideTitles: SideTitles(showTitles: false),
), // ),
bottomTitles: AxisTitles( // bottomTitles: AxisTitles(
sideTitles: SideTitles( // sideTitles: SideTitles(
showTitles: true, // showTitles: true,
reservedSize: 30, // reservedSize: 30,
interval: 12, // interval: 12,
getTitlesWidget: (value, meta) { // getTitlesWidget: (value, meta) {
switch (value.toInt()) { // switch (value.toInt()) {
case 0: // case 0:
return SideTitleWidget( // return SideTitleWidget(
axisSide: meta.axisSide, // axisSide: meta.axisSide,
child: const BodySmall(text: '1'), // child: const BodySmall(text: '1'),
); // );
case 11: // case 11:
return SideTitleWidget( // return SideTitleWidget(
axisSide: meta.axisSide, // axisSide: meta.axisSide,
child: const BodySmall(text: '28'), // child: const BodySmall(text: '28'),
); // );
default: // default:
return Container(); // return Container();
} // }
}, // },
), // ),
), // ),
leftTitles: const AxisTitles( // leftTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false), // sideTitles: SideTitles(showTitles: false),
), // ),
), // ),
minX: 0, // minX: 0,
maxX: 11, // maxX: 11,
minY: 0, // minY: 0,
maxY: 6, // maxY: 6,
lineBarsData: [ // lineBarsData: [
LineChartBarData( // LineChartBarData(
spots: const [ // spots: const [
FlSpot(0, 3), // FlSpot(0, 3),
FlSpot(2.6, 2), // FlSpot(2.6, 2),
FlSpot(4.9, 5), // FlSpot(4.9, 5),
FlSpot(6.8, 3.1), // FlSpot(6.8, 3.1),
FlSpot(8, 4), // FlSpot(8, 4),
FlSpot(9.5, 3), // FlSpot(9.5, 3),
FlSpot(11, 4), // FlSpot(11, 4),
], // ],
isCurved: true, // isCurved: true,
gradient: LinearGradient( // gradient: LinearGradient(
colors: [ // colors: [
ColorsManager.primaryColor, // ColorsManager.primaryColor,
ColorsManager.primaryColor.withOpacity(0.3), // ColorsManager.primaryColor.withOpacity(0.3),
], // ],
), // ),
barWidth: 5, // barWidth: 5,
isStrokeCapRound: true, // isStrokeCapRound: true,
dotData: const FlDotData( // dotData: const FlDotData(
show: false, // show: false,
), // ),
belowBarData: BarAreaData( // belowBarData: BarAreaData(
show: true, // show: true,
gradient: LinearGradient( // gradient: LinearGradient(
colors: [ // colors: [
ColorsManager.primaryColor.withOpacity(0.5), // ColorsManager.primaryColor.withOpacity(0.5),
ColorsManager.primaryColor.withOpacity(0.1), // ColorsManager.primaryColor.withOpacity(0.1),
], // ],
), // ),
), // ),
), // ),
], // ],
), // ),
), // ),
) // )
], // ],
), // ),
), // ),
); // );
} // }
Widget leftTitleWidgets(double value, TitleMeta meta) { // Widget leftTitleWidgets(double value, TitleMeta meta) {
String text; // String text;
switch (value.toInt()) { // switch (value.toInt()) {
case 1: // case 1:
text = '1K'; // text = '1K';
break; // break;
case 3: // case 3:
text = '3k'; // text = '3k';
break; // break;
case 5: // case 5:
text = '5k'; // text = '5k';
break; // break;
default: // default:
return Container(); // return Container();
} // }
return Center(child: BodySmall(text: text)); // return Center(child: BodySmall(text: text));
} // }
Widget bottomTitleWidgets(double value, TitleMeta meta) { // Widget bottomTitleWidgets(double value, TitleMeta meta) {
// const style = TextStyle( // // const style = TextStyle(
// fontWeight: FontWeight.bold, // // fontWeight: FontWeight.bold,
// fontSize: 16, // // fontSize: 16,
// ); // // );
// Widget text; // // Widget text;
// switch (value.toInt()) { // // switch (value.toInt()) {
// case 2: // // case 2:
// text = const Text('MAR', style: style); // // text = const Text('MAR', style: style);
// break; // // break;
// case 5: // // case 5:
// text = const Text('JUN', style: style); // // text = const Text('JUN', style: style);
// break; // // break;
// case 8: // // case 8:
// text = const Text('SEP', style: style); // // text = const Text('SEP', style: style);
// break; // // break;
// default: // // default:
// text = const Text('', style: style); // // text = const Text('', style: style);
// break; // // break;
// } // // }
return SideTitleWidget( // return SideTitleWidget(
axisSide: meta.axisSide, // axisSide: meta.axisSide,
child: const BodySmall(text: 'Feb'), // child: const BodySmall(text: 'Feb'),
); // );
} // }
} // }

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/bloc/6_scene_switch_bloc/6_scene_event.dart'; import 'package:syncrow_app/features/devices/bloc/6_scene_switch_bloc/6_scene_event.dart';
import 'package:syncrow_app/features/devices/bloc/6_scene_switch_bloc/6_scene_state.dart'; import 'package:syncrow_app/features/devices/bloc/6_scene_switch_bloc/6_scene_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart';
@ -16,6 +17,7 @@ import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart'; import 'package:syncrow_app/services/api/home_management_api.dart';
import 'package:syncrow_app/services/api/scene_api.dart'; import 'package:syncrow_app/services/api/scene_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> { class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
@ -112,8 +114,9 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
FetchRoomsEvent event, Emitter<SixSceneState> emit) async { FetchRoomsEvent event, Emitter<SixSceneState> emit) async {
try { try {
emit(SixSceneLoadingState()); emit(SixSceneLoadingState());
Project? project = HomeCubit.getInstance().project;
roomsList = await SpacesAPI.getSubSpaceBySpaceId( roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id); event.unit.community.uuid, event.unit.id, project?.uuid ?? TempConst.projectIdDev);
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList)); emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
} catch (e) { } catch (e) {
emit(SixSceneFailedState(errorMessage: e.toString())); emit(SixSceneFailedState(errorMessage: e.toString()));
@ -125,12 +128,14 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
try { try {
emit(SixSceneLoadingState()); emit(SixSceneLoadingState());
if (_hasSelectionChanged) { if (_hasSelectionChanged) {
Project? project = HomeCubit.getInstance().project;
await HomeManagementAPI.assignDeviceToRoom( await HomeManagementAPI.assignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, sixSceneId); event.unit.community.uuid, event.unit.id, event.roomId, sixSceneId, project?.uuid ?? TempConst.projectIdDev);
final devicesList = await DevicesAPI.getDevicesByRoomId( final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid, communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id, spaceUuid: event.unit.id,
roomId: event.roomId); roomId: event.roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
List<String> allDevicesIds = []; List<String> allDevicesIds = [];
allDevices.forEach((element) { allDevices.forEach((element) {
allDevicesIds.add(element.uuid!); allDevicesIds.add(element.uuid!);
@ -341,8 +346,10 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
emit(SixSceneLoadingState()); emit(SixSceneLoadingState());
try { try {
Project? project = HomeCubit.getInstance().project;
allScenes = await SceneApi.getScenesByUnitId( allScenes = await SceneApi.getScenesByUnitId(
event.unitId, event.unit.community.uuid, event.unitId, event.unit.community.uuid, project?.uuid ?? TempConst.projectIdDev,
showInDevice: event.showInDevice); showInDevice: event.showInDevice);
filteredScenes = allScenes; filteredScenes = allScenes;

View File

@ -27,7 +27,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
bool allAcsPage = false; bool allAcsPage = false;
bool allAcsOn = true; bool allAcsOn = true;
bool allTempSame = true; bool allTempSame = true;
int globalTemp = 25; int globalTemp = 250;
Timer? _timer; Timer? _timer;
ACsBloc({required this.acId}) : super(AcsInitialState()) { ACsBloc({required this.acId}) : super(AcsInitialState()) {
@ -68,11 +68,10 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
} }
deviceStatus = deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
AcStatusModel.fromJson(response['productUuid'], statusModelList);
emit(GetAcStatusState(acStatusModel: deviceStatus)); emit(GetAcStatusState(acStatusModel: deviceStatus));
Future.delayed(const Duration(milliseconds: 500)); Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges(); _listenToChanges(acId);
} }
} catch (e) { } catch (e) {
emit(AcsFailedState(errorMessage: e.toString())); emit(AcsFailedState(errorMessage: e.toString()));
@ -80,29 +79,38 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
} }
} }
_listenToChanges() { StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges(acId) {
try { try {
_streamSubscription?.cancel();
DatabaseReference ref = DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$acId'); FirebaseDatabase.instance.ref('device-status/$acId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) { _streamSubscription = stream.listen((DatabaseEvent event) {
Map<dynamic, dynamic> usersMap = Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>; event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList statusList.add(StatusModel(code: element['code'], value: element['value']));
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = deviceStatus =
AcStatusModel.fromJson(usersMap['productUuid'], statusList); AcStatusModel.fromJson(usersMap['productUuid'], statusList);
add(AcUpdated()); add(AcUpdated());
}); });
} catch (_) {} } catch (_) {}
} }
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_onAcUpdated(AcUpdated event, Emitter<AcsState> emit) { _onAcUpdated(AcUpdated event, Emitter<AcsState> emit) {
emit(GetAcStatusState(acStatusModel: deviceStatus)); emit(GetAcStatusState(acStatusModel: deviceStatus));
} }
@ -114,15 +122,16 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC'); HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
_listenToChanges(devicesList[i].uuid);
var response = var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
} }
deviceStatusList.add( deviceStatusList.add(AcStatusModel.fromJson(devicesList[i].uuid ?? '', statusModelList));
AcStatusModel.fromJson(response['productUuid'], statusModelList));
} }
_setAllAcsTempsAndSwitches(); _setAllAcsTempsAndSwitches();
} }
@ -131,10 +140,11 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (allAcsPage) { if (allAcsPage) {
emit(AcsLoadingState()); emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) { for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.productId) { if (ac.uuid == event.deviceId) {
ac.acSwitch = acSwitchValue; ac.acSwitch = acSwitchValue;
} }
} }
_setAllAcsTempsAndSwitches(); _setAllAcsTempsAndSwitches();
_emitAcsStatus(emit); _emitAcsStatus(emit);
} else { } else {
@ -143,8 +153,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
} }
void _changeAllAcSwitch(ChangeAllSwitch event, Emitter<AcsState> emit) async { void _changeAllAcSwitch(ChangeAllSwitch event, Emitter<AcsState> emit) async {
@ -205,8 +214,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
deviceStatus.childLock = lockValue; deviceStatus.childLock = lockValue;
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue);
deviceId: acId, code: 'child_lock', value: lockValue);
} }
void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async { void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async {
@ -222,7 +230,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (allAcsPage) { if (allAcsPage) {
emit(AcsLoadingState()); emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) { for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.productId) { if (ac.uuid == event.deviceId) {
ac.tempSet = value; ac.tempSet = value;
} }
} }
@ -234,8 +242,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
deviceId: event.deviceId, code: 'temp_set', value: value);
} }
void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter<AcsState> emit) async { void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter<AcsState> emit) async {
@ -251,7 +258,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (allAcsPage) { if (allAcsPage) {
emit(AcsLoadingState()); emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) { for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.productId) { if (ac.uuid == event.deviceId) {
ac.tempSet = value; ac.tempSet = value;
} }
} }
@ -263,8 +270,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
deviceId: event.deviceId, code: 'temp_set', value: value);
} }
void _changeAcMode(ChangeAcMode event, Emitter<AcsState> emit) async { void _changeAcMode(ChangeAcMode event, Emitter<AcsState> emit) async {
@ -272,7 +278,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (allAcsPage) { if (allAcsPage) {
emit(AcsLoadingState()); emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) { for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.productId) { if (ac.uuid == event.deviceId) {
ac.modeString = getACModeString(tempMode); ac.modeString = getACModeString(tempMode);
ac.acMode = AcStatusModel.getACMode(getACModeString(tempMode)); ac.acMode = AcStatusModel.getACMode(getACModeString(tempMode));
} }
@ -286,9 +292,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
} }
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(
deviceId: event.deviceId, deviceId: event.deviceId, code: 'mode', value: getACModeString(tempMode));
code: 'mode',
value: getACModeString(tempMode));
} }
void _changeFanSpeed(ChangeFanSpeed event, Emitter<AcsState> emit) async { void _changeFanSpeed(ChangeFanSpeed event, Emitter<AcsState> emit) async {
@ -299,25 +303,21 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (allAcsPage) { if (allAcsPage) {
emit(AcsLoadingState()); emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) { for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.productId) { if (ac.uuid == event.deviceId) {
ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed); ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
ac.acFanSpeed = ac.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
} }
} }
_emitAcsStatus(emit); _emitAcsStatus(emit);
} else { } else {
emit(AcChangeLoading(acStatusModel: deviceStatus)); emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed); deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
deviceStatus.acFanSpeed = deviceStatus.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
emit(AcModifyingState(acStatusModel: deviceStatus)); emit(AcModifyingState(acStatusModel: deviceStatus));
} }
await _runDeBouncerForOneDevice( await _runDeBouncerForOneDevice(
deviceId: event.deviceId, deviceId: event.deviceId, code: 'level', value: getNextFanSpeedKey(fanSpeed));
code: 'level',
value: getNextFanSpeedKey(fanSpeed));
} }
String getACModeString(TempModes value) { String getACModeString(TempModes value) {
@ -336,17 +336,15 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
allAcsOn = true; allAcsOn = true;
allTempSame = true; allTempSame = true;
if (deviceStatusList.isNotEmpty) { if (deviceStatusList.isNotEmpty) {
int temp = deviceStatusList[0].tempSet; int temp = deviceStatusList.first.tempSet;
deviceStatusList.firstWhere((element) { for (var element in deviceStatusList) {
if (!element.acSwitch) { if (!element.acSwitch) {
allAcsOn = false; allAcsOn = false;
} }
if (element.tempSet != temp) { if (element.tempSet != temp) {
allTempSame = false; allTempSame = false;
} }
}
return true;
});
if (allTempSame) { if (allTempSame) {
globalTemp = temp; globalTemp = temp;
} }
@ -362,8 +360,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
for (int i = 0; i < deviceStatusList.length; i++) { for (int i = 0; i < deviceStatusList.length; i++) {
try { try {
await DevicesAPI.controlDevice( await DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(deviceId: devicesList[i].uuid, code: code, value: value),
deviceId: devicesList[i].uuid, code: code, value: value),
devicesList[i].uuid ?? ''); devicesList[i].uuid ?? '');
} catch (_) { } catch (_) {
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 500));
@ -385,10 +382,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
_timer = Timer(const Duration(seconds: 1), () async { _timer = Timer(const Duration(seconds: 1), () async {
try { try {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(deviceId: allAcsPage ? deviceId : acId, code: code, value: value),
deviceId: allAcsPage ? deviceId : acId,
code: code,
value: value),
allAcsPage ? deviceId : acId); allAcsPage ? deviceId : acId);
if (!response['success']) { if (!response['success']) {
@ -405,8 +399,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
if (value >= 20 && value <= 30) { if (value >= 20 && value <= 30) {
return true; return true;
} else { } else {
emit(const AcsFailedState( emit(const AcsFailedState(errorMessage: 'The temperature must be between 20 and 30'));
errorMessage: 'The temperature must be between 20 and 30'));
emit(GetAllAcsStatusState( emit(GetAllAcsStatusState(
allAcsStatues: deviceStatusList, allAcsStatues: deviceStatusList,
allAcs: devicesList, allAcs: devicesList,
@ -432,9 +425,7 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
try { try {
seconds = event.seconds; seconds = event.seconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(deviceId: acId, code: 'countdown_time', value: event.duration), acId);
deviceId: acId, code: 'countdown_time', value: event.duration),
acId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
deviceStatus.countdown1 = seconds; deviceStatus.countdown1 = seconds;
@ -455,24 +446,26 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
} }
void _getCounterValue(GetCounterEvent event, Emitter<AcsState> emit) async { void _getCounterValue(GetCounterEvent event, Emitter<AcsState> emit) async {
try { emit(AcsLoadingState());
emit(AcsLoadingState()); var response = await DevicesAPI.getDeviceStatus(acId);
var response = await DevicesAPI.getDeviceStatus(acId); List<StatusModel> statusModelList = [];
List<StatusModel> statusModelList = []; for (var status in response['status']) {
for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status));
statusModelList.add(StatusModel.fromJson(status)); }
} deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
deviceStatus = deviceStatus.countdown1;
AcStatusModel.fromJson(response['productUuid'], statusModelList); var duration;
if (deviceStatus.countdown1 == 5) {
if (event.deviceCode == 'countdown_time') { duration = const Duration(minutes: 30);
deviceStatus.countdown1 > 0 var countNum = duration.inSeconds;
? _onStartTimer(deviceStatus.countdown1) _onStartTimer(countNum);
: emit(UpdateTimerState(seconds: deviceStatus.countdown1)); } else if (deviceStatus.countdown1 > 5) {
} duration = Duration(minutes: deviceStatus.countdown1 * 6);
} catch (e) { var countNum = duration.inSeconds;
emit(AcsFailedState(errorMessage: e.toString())); _onStartTimer(countNum);
return; } else {
_timer?.cancel();
emit(TimerRunComplete());
} }
} }

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -33,35 +35,49 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
} }
deviceStatus = CeilingSensorModel.fromJson(statusModelList); deviceStatus = CeilingSensorModel.fromJson(statusModelList);
emit(UpdateState(ceilingSensorModel: deviceStatus)); emit(UpdateState(ceilingSensorModel: deviceStatus));
// _listenToChanges(); _listenToChanges();
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
_listenToChanges() { StreamSubscription<DatabaseEvent>? _streamSubscription;
Timer? _timer;
void _listenToChanges() {
try { try {
_streamSubscription?.cancel();
DatabaseReference ref = DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$deviceId'); FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) { _streamSubscription = stream.listen((DatabaseEvent event) async {
if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap = Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>; event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList statusList
.add(StatusModel(code: element['code'], value: element['value'])); .add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = CeilingSensorModel.fromJson(statusList); deviceStatus = CeilingSensorModel.fromJson(statusList);
add(CeilingSensorUpdated()); if (!isClosed) {
add(CeilingSensorUpdated());
}
}); });
} catch (_) {} } catch (_) {}
} }
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_onCeilingSensorUpdated( _onCeilingSensorUpdated(
CeilingSensorUpdated event, Emitter<CeilingSensorState> emit) { CeilingSensorUpdated event, Emitter<CeilingSensorState> emit) {
emit(UpdateState(ceilingSensorModel: deviceStatus)); emit(UpdateState(ceilingSensorModel: deviceStatus));
@ -112,7 +128,7 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
code: 'presence_state', code: 'presence_state',
); );
recordGroups = response; recordGroups = response;
// print('---${recordGroups.data!.first.eventTime}'); // print('---${jsonEncode(recordGroups.data.first.)}');
emit(FitchData()); emit(FitchData());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart'; import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dart';
@ -30,6 +32,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
on<InitialWizardEvent>(_fetchWizardStatus); on<InitialWizardEvent>(_fetchWizardStatus);
on<GroupAllOffEvent>(_groupAllOff); on<GroupAllOffEvent>(_groupAllOff);
on<GroupAllOnEvent>(_groupAllOn); on<GroupAllOnEvent>(_groupAllOn);
on<UpdateCurtainEvent>(_updateCurtain);
} }
Future<void> _onOpenCurtain( Future<void> _onOpenCurtain(
@ -161,7 +164,10 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
void _fetchStatus(InitCurtain event, Emitter<CurtainState> emit) async { void _fetchStatus(InitCurtain event, Emitter<CurtainState> emit) async {
try { try {
emit(CurtainLoadingState()); emit(CurtainLoadingState());
_listenToChanges(curtainId);
var response = await DevicesAPI.getDeviceStatus(curtainId); var response = await DevicesAPI.getDeviceStatus(curtainId);
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -169,7 +175,6 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
openPercentage = double.tryParse(statusModelList[1].value.toString())!; openPercentage = double.tryParse(statusModelList[1].value.toString())!;
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
emit(CurtainsOpening( emit(CurtainsOpening(
curtainWidth: curtainWidth, curtainWidth: curtainWidth,
blindHeight: blindHeight, blindHeight: blindHeight,
@ -181,6 +186,76 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
} }
} }
StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges(curtainId) {
try {
_streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$curtainId');
Stream<DatabaseEvent> stream = ref.onValue;
_streamSubscription = 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']));
});
openPercentage = double.tryParse(statusList[1].value.toString())!;
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
add(UpdateCurtainEvent());
});
} catch (_) {}
}
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
// _listenToChanges(curtainId) {
// try {
// print('curtainId=$curtainId');
// DatabaseReference ref =
// FirebaseDatabase.instance.ref('device-status/$curtainId');
// 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> statusModelList = [];
// for (var status in usersMap['status']) {
// statusModelList.add(StatusModel.fromJson(status));
// print('statusModelList==${statusModelList}');
// }
// openPercentage = double.tryParse(statusModelList[1].value.toString())!;
// curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
// blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
// add(UpdateCurtainEvent());
// });
// } catch (_) {}
// }
_updateCurtain(UpdateCurtainEvent event, Emitter<CurtainState> emit) {
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
emit(CurtainsOpening(
curtainWidth: curtainWidth,
blindHeight: blindHeight,
openPercentage: openPercentage,
));
}
List<GroupCurtainModel> groupList = []; List<GroupCurtainModel> groupList = [];
bool allSwitchesOn = true; bool allSwitchesOn = true;
List<DeviceModel> devicesList = []; List<DeviceModel> devicesList = [];

View File

@ -33,6 +33,7 @@ class InitCurtain extends CurtainEvent {}
class PauseCurtain extends CurtainEvent {} class PauseCurtain extends CurtainEvent {}
class useCurtainEvent extends CurtainEvent {} class useCurtainEvent extends CurtainEvent {}
class InitialWizardEvent extends CurtainEvent {} class InitialWizardEvent extends CurtainEvent {}
class UpdateCurtainEvent extends CurtainEvent {}
class ChangeFirstWizardSwitchStatusEvent extends CurtainEvent { class ChangeFirstWizardSwitchStatusEvent extends CurtainEvent {

View File

@ -2,6 +2,8 @@ import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_event.dart'; import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_event.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_state.dart'; import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_state.dart';
@ -10,6 +12,7 @@ import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart'; import 'package:syncrow_app/services/api/home_management_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> { class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
@ -27,11 +30,16 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
static List<DevicesCategoryModel>? allCategories; static List<DevicesCategoryModel>? allCategories;
Future<void> _onFetchAllDevices(FetchAllDevices event, Emitter<DeviceManagerState> emit) async { Future<void> _onFetchAllDevices(
FetchAllDevices event, Emitter<DeviceManagerState> emit) async {
emit(state.copyWith(loading: true)); emit(state.copyWith(loading: true));
try { try {
final allDevices = await HomeManagementAPI.fetchDevicesByUnitId(); Project? project = HomeCubit.getInstance().project;
emit(state.copyWith(devices: _getOnlyImplementedDevices(allDevices), loading: false));
final allDevices = await HomeManagementAPI.fetchDevicesByUnitId(
project?.uuid ?? TempConst.projectIdDev);
emit(state.copyWith(
devices: _getOnlyImplementedDevices(allDevices), loading: false));
} catch (e) { } catch (e) {
emit(state.copyWith(error: e.toString(), loading: false)); emit(state.copyWith(error: e.toString(), loading: false));
} }
@ -41,26 +49,31 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
FetchDevicesByRoomId event, Emitter<DeviceManagerState> emit) async { FetchDevicesByRoomId event, Emitter<DeviceManagerState> emit) async {
emit(state.copyWith(loading: true)); emit(state.copyWith(loading: true));
try { try {
final devices = await DevicesAPI.getDevicesByRoomId( Project? project = HomeCubit.getInstance().project;
communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id,
roomId: event.roomId,
);
emit(state.copyWith(devices: _getOnlyImplementedDevices(devices), loading: false)); final devices = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id,
roomId: event.roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
emit(state.copyWith(
devices: _getOnlyImplementedDevices(devices), loading: false));
} catch (e) { } catch (e) {
emit(state.copyWith(error: e.toString(), loading: false)); emit(state.copyWith(error: e.toString(), loading: false));
} }
} }
void _onSelectCategory(SelectCategory event, Emitter<DeviceManagerState> emit) { void _onSelectCategory(
SelectCategory event, Emitter<DeviceManagerState> emit) {
for (var i = 0; i < allCategories!.length; i++) { for (var i = 0; i < allCategories!.length; i++) {
allCategories![i].isSelected = i == event.index; allCategories![i].isSelected = i == event.index;
} }
emit(state.copyWith(categoryChanged: true)); emit(state.copyWith(categoryChanged: true));
} }
void _onUnselectAllCategories(UnselectAllCategories event, Emitter<DeviceManagerState> emit) { void _onUnselectAllCategories(
UnselectAllCategories event, Emitter<DeviceManagerState> emit) {
for (var category in allCategories!) { for (var category in allCategories!) {
category.isSelected = false; category.isSelected = false;
} }
@ -104,7 +117,8 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
_updateDevicesStatus(category, emit); _updateDevicesStatus(category, emit);
} }
void _onTurnOnOffDevice(TurnOnOffDevice event, Emitter<DeviceManagerState> emit) { void _onTurnOnOffDevice(
TurnOnOffDevice event, Emitter<DeviceManagerState> emit) {
var device = event.device; var device = event.device;
device.isOnline = !device.isOnline!; device.isOnline = !device.isOnline!;
DevicesCategoryModel category = allCategories!.firstWhere((category) { DevicesCategoryModel category = allCategories!.firstWhere((category) {
@ -127,7 +141,8 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
emit(state.copyWith(categoryChanged: true)); // Set category changed state emit(state.copyWith(categoryChanged: true)); // Set category changed state
} }
void _updateDevicesStatus(DevicesCategoryModel category, Emitter<DeviceManagerState> emit) { void _updateDevicesStatus(
DevicesCategoryModel category, Emitter<DeviceManagerState> emit) {
if (category.devices != null && category.devices!.isNotEmpty) { if (category.devices != null && category.devices!.isNotEmpty) {
bool? tempStatus = category.devices![0].isOnline; bool? tempStatus = category.devices![0].isOnline;
for (var device in category.devices!) { for (var device in category.devices!) {
@ -147,7 +162,8 @@ class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
try { try {
final deviceFunctions = await DevicesAPI.deviceFunctions(event.deviceId); final deviceFunctions = await DevicesAPI.deviceFunctions(event.deviceId);
emit(state.copyWith(functionsLoading: false, deviceFunctions: deviceFunctions)); emit(state.copyWith(
functionsLoading: false, deviceFunctions: deviceFunctions));
} catch (e) { } catch (e) {
emit(state.copyWith(functionsLoading: false, error: e.toString())); emit(state.copyWith(functionsLoading: false, error: e.toString()));
} }

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/bloc/device_settings_bloc/device_scene_event.dart'; import 'package:syncrow_app/features/devices/bloc/device_settings_bloc/device_scene_event.dart';
import 'package:syncrow_app/features/devices/bloc/device_settings_bloc/device_scene_state.dart'; import 'package:syncrow_app/features/devices/bloc/device_settings_bloc/device_scene_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
@ -18,6 +19,7 @@ import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart'; import 'package:syncrow_app/services/api/home_management_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class DeviceSettingBloc extends Bloc<DeviceSettingEvent, DeviceSettingState> { class DeviceSettingBloc extends Bloc<DeviceSettingEvent, DeviceSettingState> {
@ -349,13 +351,20 @@ class DeviceSettingBloc extends Bloc<DeviceSettingEvent, DeviceSettingState> {
AssignRoomEvent event, Emitter<DeviceSettingState> emit) async { AssignRoomEvent event, Emitter<DeviceSettingState> emit) async {
try { try {
emit(DeviceSettingLoadingState()); emit(DeviceSettingLoadingState());
Project? project = HomeCubit.getInstance().project;
if (_hasSelectionChanged) { if (_hasSelectionChanged) {
await HomeManagementAPI.assignDeviceToRoom( await HomeManagementAPI.assignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, deviceId); event.unit.community.uuid,
event.unit.id,
event.roomId,
deviceId,
project?.uuid ?? TempConst.projectIdDev);
final devicesList = await DevicesAPI.getDevicesByRoomId( final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid, communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id, spaceUuid: event.unit.id,
roomId: event.roomId); roomId: event.roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
List<String> allDevicesIds = []; List<String> allDevicesIds = [];
allDevices.forEach((element) { allDevices.forEach((element) {
allDevicesIds.add(element.uuid!); allDevicesIds.add(element.uuid!);
@ -375,8 +384,12 @@ class DeviceSettingBloc extends Bloc<DeviceSettingEvent, DeviceSettingState> {
FetchRoomsEvent event, Emitter<DeviceSettingState> emit) async { FetchRoomsEvent event, Emitter<DeviceSettingState> emit) async {
try { try {
emit(DeviceSettingLoadingState()); emit(DeviceSettingLoadingState());
Project? project = HomeCubit.getInstance().project;
roomsList = await SpacesAPI.getSubSpaceBySpaceId( roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id); event.unit.community.uuid,
event.unit.id,
project?.uuid ?? TempConst.projectIdDev);
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList)); emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
} catch (e) { } catch (e) {
emit( emit(

View File

@ -1,10 +1,14 @@
// ignore_for_file: constant_identifier_names, unused_import // ignore_for_file: constant_identifier_names, unused_import
import 'dart:async';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart'; import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart'; import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
@ -19,6 +23,7 @@ import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart'; import 'package:syncrow_app/services/api/home_management_api.dart';
import 'package:syncrow_app/services/api/network_exception.dart'; import 'package:syncrow_app/services/api/network_exception.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
part 'devices_state.dart'; part 'devices_state.dart';
@ -31,6 +36,7 @@ class DevicesCubit extends Cubit<DevicesState> {
// Fetch groups based on the selected space ID // Fetch groups based on the selected space ID
await fetchGroups(selectedSpace.id); await fetchGroups(selectedSpace.id);
await fetchAllDevices(selectedSpace);
} }
DevicesCubit._() : super(DevicesInitial()) { DevicesCubit._() : super(DevicesInitial()) {
@ -60,6 +66,43 @@ class DevicesCubit extends Cubit<DevicesState> {
} }
} }
Timer? _timer;
final Map<String, StreamSubscription<DatabaseEvent>> _deviceSubscriptions =
{};
void _listenToChanges(deviceId) {
try {
if (_deviceSubscriptions.containsKey(deviceId)) {
_deviceSubscriptions[deviceId]?.cancel();
_deviceSubscriptions.remove(deviceId);
}
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue;
final subscription = 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>;
// print('object-----${usersMap['status']}');
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
emitSafe(GetDevicesLoading());
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceId);
if (deviceIndex != -1) {
allDevices[deviceIndex].status = statusList;
}
emitSafe(GetDevicesSuccess(allDevices));
});
_deviceSubscriptions[deviceId] = subscription;
} catch (_) {}
}
static DevicesCubit get(context) => BlocProvider.of(context); static DevicesCubit get(context) => BlocProvider.of(context);
List<DevicesCategoryModel>? allCategories; List<DevicesCategoryModel>? allCategories;
@ -109,17 +152,6 @@ class DevicesCubit extends Cubit<DevicesState> {
} }
// Getter to retrieve all devices from HomeCubit // Getter to retrieve all devices from HomeCubit
List<DeviceModel> get allDevices {
List<DeviceModel> devices = [];
if (HomeCubit.getInstance().selectedSpace != null) {
for (var room in HomeCubit.getInstance().selectedSpace!.subspaces) {
if (room.devices != null) {
devices.addAll(room.devices!);
}
}
}
return devices;
}
// DevicesCategoryModel? get chosenCategory { // DevicesCategoryModel? get chosenCategory {
// for (var category in allCategories!) { // for (var category in allCategories!) {
@ -267,36 +299,36 @@ class DevicesCubit extends Cubit<DevicesState> {
} }
///////////////////////// API CALLS ////////////////////////// ///////////////////////// API CALLS //////////////////////////
deviceControl(DeviceControlModel control, String deviceId) async { // deviceControl(DeviceControlModel control, String deviceId) async {
emitSafe(DeviceControlLoading( // emitSafe(DeviceControlLoading(
code: control.code, // code: control.code,
)); // ));
try { // try {
var response = await DevicesAPI.controlDevice(control, deviceId); // var response = await DevicesAPI.controlDevice(control, deviceId);
if (response['success'] ?? false) { // if (response['success'] ?? false) {
emitSafe(DeviceControlSuccess(code: control.code)); // emitSafe(DeviceControlSuccess(code: control.code));
//this delay is to give tuya server time to update the status // //this delay is to give tuya server time to update the status
// Future.delayed(const Duration(milliseconds: 400), () { // // Future.delayed(const Duration(milliseconds: 400), () {
fetchDevicesStatues( // fetchDevicesStatues(
deviceId, // deviceId,
HomeCubit.getInstance() // HomeCubit.getInstance()
.selectedSpace! // .selectedSpace!
.subspaces // .subspaces
.indexOf(HomeCubit.getInstance().selectedRoom!), // .indexOf(HomeCubit.getInstance().selectedRoom!),
code: control.code); // code: control.code);
// }); // // });
} else { // } else {
emitSafe(DeviceControlError('Failed to control the device')); // emitSafe(DeviceControlError('Failed to control the device'));
} // }
} catch (failure) { // } catch (failure) {
emitSafe(DeviceControlError(failure.toString())); // emitSafe(DeviceControlError(failure.toString()));
return; // return;
} // }
} // }
fetchGroups(String spaceId) async { fetchGroups(String spaceId) async {
emitSafe(DevicesCategoriesLoading()); emitSafe(GetDevicesLoading());
try { try {
allCategories = await DevicesAPI.fetchGroups(spaceId); allCategories = await DevicesAPI.fetchGroups(spaceId);
} catch (e) { } catch (e) {
@ -319,14 +351,20 @@ class DevicesCubit extends Cubit<DevicesState> {
.subspaces .subspaces
.indexWhere((element) => element.id == roomId); .indexWhere((element) => element.id == roomId);
try { try {
Project? project = HomeCubit.getInstance().project;
HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices = HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices =
await DevicesAPI.getDevicesByRoomId( await DevicesAPI.getDevicesByRoomId(
communityUuid: unit!.community.uuid, spaceUuid: unit.id, roomId: roomId); communityUuid: unit!.community.uuid,
spaceUuid: unit.id,
roomId: roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
} catch (e) { } catch (e) {
emitSafe(GetDevicesError(e.toString())); emitSafe(GetDevicesError(e.toString()));
return; return;
} }
final devices = HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices; final devices =
HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices;
emitSafe(GetDevicesSuccess(devices)); emitSafe(GetDevicesSuccess(devices));
//get status for each device //get status for each device
@ -356,8 +394,11 @@ class DevicesCubit extends Cubit<DevicesState> {
emitSafe(GetDeviceStatusError(e.toString())); emitSafe(GetDeviceStatusError(e.toString()));
return; return;
} }
HomeCubit.getInstance().selectedSpace!.subspaces[roomIndex].devices![deviceIndex].status = HomeCubit.getInstance()
statuses; .selectedSpace!
.subspaces[roomIndex]
.devices![deviceIndex]
.status = statuses;
emitSafe(GetDeviceStatusSuccess(code: code)); emitSafe(GetDeviceStatusSuccess(code: code));
} }
@ -406,6 +447,365 @@ class DevicesCubit extends Cubit<DevicesState> {
// emitSafe(LightBrightnessChanged(value)); // emitSafe(LightBrightnessChanged(value));
// } // }
// } // }
// List<DeviceModel> _fetchedDevices = [];
// List<DeviceModel> get allDevices => _fetchedDevices;
List<DeviceModel> allDevices = [];
Future<void> fetchAllDevices(SpaceModel? unit) async {
emitSafe(GetDevicesLoading());
try {
Project? project = HomeCubit.getInstance().project;
final devices = await DevicesAPI.getAllDevices(
communityUuid: unit!.community.uuid,
spaceUuid: unit.id,
projectId: project?.uuid ?? TempConst.projectIdDev);
allDevices = devices;
for (var deviceId in allDevices) {
if (deviceId.type == "3G" ||
deviceId.type == "2G" ||
deviceId.type == "1G" ||
deviceId.type == "3GT" ||
deviceId.type == "2GT" ||
deviceId.type == "1GT" ||
deviceId.type == "WH" ||
deviceId.type == "CUR" ||
deviceId.type == "AC") {
_listenToChanges(deviceId.uuid);
}
}
emitSafe(GetDevicesSuccess(allDevices));
} catch (e) {
emitSafe(GetDevicesError(e.toString()));
}
}
bool isDeviceOn(DeviceModel device) {
final switchStatuses = device.status.where(
(s) => (s.code?.startsWith('switch') ?? false),
);
final anySwitchFalse = switchStatuses.any((s) => s.value == false);
return !anySwitchFalse;
}
void updateDeviceStatus(String deviceId, bool newToggleStatus) {
emitSafe(GetDevicesLoading());
// Create a fresh copy of the device list.
final updatedDevices = List<DeviceModel>.from(allDevices);
for (int i = 0; i < updatedDevices.length; i++) {
final device = updatedDevices[i];
if (device.uuid == deviceId) {
updatedDevices[i] = DeviceModel(
activeTime: device.activeTime,
localKey: device.localKey,
model: device.model,
name: device.name,
icon: device.icon,
categoryName: device.categoryName,
type: device.type,
isOnline: device.isOnline,
status: device.status, // Make sure to keep the same status list
productName: device.productName,
timeZone: device.timeZone,
updateTime: device.updateTime,
uuid: device.uuid,
productUuid: device.productUuid,
productType: device.productType,
subspace: device.subspace,
toggleStatus: newToggleStatus,
);
break;
}
}
emit(GetDevicesSuccess(updatedDevices));
}
Future<void> threeGangToggle(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex == -1) {
throw Exception('Device not found');
}
final device = allDevices[deviceIndex];
final switches = ['switch_1', 'switch_2', 'switch_3'];
final anySwitchOff = device.status.any(
(s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
);
final targetState = anySwitchOff ? true : false;
for (final switchCode in switches) {
final statusIndex =
device.status.indexWhere((s) => s.code == switchCode);
if (statusIndex != -1) {
final currentValue = device.status[statusIndex].value ?? false;
if (!targetState && !currentValue) {
continue;
}
final controlRequest = DeviceControlModel(
code: switchCode, value: targetState, deviceId: deviceUuid);
final response =
await DevicesAPI.controlDevice(controlRequest, deviceUuid);
if (response['success'] != true) {
throw Exception('Failed to toggle $switchCode');
}
device.status[statusIndex].value = targetState;
}
}
device.toggleStatus = device.status.every(
(s) => (s.code?.startsWith('switch_') ?? false) && (s.value == true),
);
allDevices[deviceIndex] = device;
emit(DeviceControlSuccess(code: control.code));
} catch (failure) {
emit(DeviceControlError(failure.toString()));
}
}
Future<void> towGangToggle(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex == -1) {
throw Exception('Device not found');
}
final device = allDevices[deviceIndex];
final switches = [
'switch_1',
'switch_2',
];
for (final switchCode in switches) {
final statusIndex =
device.status.indexWhere((s) => s.code == switchCode);
if (statusIndex != -1) {
final toggledValue = control.value;
final controlRequest = DeviceControlModel(
code: switchCode, value: toggledValue, deviceId: deviceUuid);
final response =
await DevicesAPI.controlDevice(controlRequest, deviceUuid);
device.status[statusIndex].value = response['result'];
}
}
final anySwitchOff = device.status.any(
(s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
);
device.toggleStatus = !anySwitchOff;
allDevices[deviceIndex] = device;
emit(DeviceControlSuccess(code: control.code));
} catch (failure) {
emit(DeviceControlError(failure.toString()));
}
}
Future<void> towGTGangToggle(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex == -1) {
throw Exception('Device not found');
}
final device = allDevices[deviceIndex];
final switches = [
'switch_1',
'switch_2',
];
for (final switchCode in switches) {
final statusIndex =
device.status.indexWhere((s) => s.code == switchCode);
if (statusIndex != -1) {
final toggledValue = control.value;
final controlRequest = DeviceControlModel(
code: switchCode, value: toggledValue, deviceId: deviceUuid);
final response =
await DevicesAPI.controlDevice(controlRequest, deviceUuid);
device.status[statusIndex].value = response['result'];
}
}
final anySwitchOff = device.status.any(
(s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
);
device.toggleStatus = !anySwitchOff;
allDevices[deviceIndex] = device;
emit(DeviceControlSuccess(code: control.code));
} catch (failure) {
emit(DeviceControlError(failure.toString()));
}
}
Future<void> oneGangToggle(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex == -1) {
throw Exception('Device not found');
}
final device = allDevices[deviceIndex];
final statusIndex = device.status.indexWhere((s) => s.code == 'switch_1');
if (statusIndex != -1) {
final toggledValue = control.value;
final controlRequest = DeviceControlModel(
code: 'switch_1', value: toggledValue, deviceId: deviceUuid);
final response =
await DevicesAPI.controlDevice(controlRequest, deviceUuid);
if (response['result'] != true) {
throw Exception('Failed to toggle switch_1');
}
device.status[statusIndex].value = response['result'];
}
final anySwitchOff = device.status.any(
(s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
);
device.toggleStatus = !anySwitchOff;
allDevices[deviceIndex] = device;
emit(DeviceControlSuccess(code: control.code));
} catch (failure) {
emit(DeviceControlError(failure.toString()));
}
}
Future<void> oneGTGangToggle(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex == -1) {
throw Exception('Device not found');
}
final device = allDevices[deviceIndex];
final statusIndex = device.status.indexWhere((s) => s.code == 'switch_1');
if (statusIndex != -1) {
final currentValue = device.status[statusIndex].value ?? false;
final toggledValue = !currentValue;
final controlRequest = DeviceControlModel(
code: 'switch_1', value: toggledValue, deviceId: deviceUuid);
final response =
await DevicesAPI.controlDevice(controlRequest, deviceUuid);
if (response['result'] != true) {
throw Exception('Failed to toggle switch_1');
}
device.status[statusIndex].value = response['result'];
}
final anySwitchOff = device.status.any(
(s) => (s.code?.startsWith('switch_') ?? false) && (s.value == false),
);
device.toggleStatus = !anySwitchOff;
allDevices[deviceIndex] = device;
emit(DeviceControlSuccess(code: control.code));
} catch (failure) {
emit(DeviceControlError(failure.toString()));
}
}
Future<void> deviceControl(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final response = await DevicesAPI.controlDevice(control, deviceUuid);
if (response['success'] == true) {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex != -1) {
final device = allDevices[deviceIndex];
final statusIndex =
device.status.indexWhere((s) => s.code == control.code);
if (statusIndex != -1) {
device.status[statusIndex].value = control.value;
}
final anySwitchOff = device.status.any(
(s) =>
(s.code?.startsWith('switch_') ?? false) && (s.value == false),
);
device.toggleStatus = !anySwitchOff;
allDevices[deviceIndex] = device;
}
emit(DeviceControlSuccess(code: control.code));
} else {
emit(DeviceControlError('Failed to control the device'));
}
} catch (failure) {
emit(DeviceControlError(failure.toString()));
}
}
Future<void> changeCurtainSwitch(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex == -1) {
throw Exception('Device not found');
}
final device = allDevices[deviceIndex];
final isOpen = control.value == "open";
final newValue = isOpen ? 0 : 100;
final response = await DevicesAPI.deviceBatchController(
code: 'percent_control',
devicesUuid: [deviceUuid],
value: newValue,
);
if (response['success'] == true) {
final statusIndex =
device.status.indexWhere((s) => s.code == 'percent_control');
if (statusIndex != -1) {
device.status[statusIndex].value = newValue;
}
allDevices[deviceIndex] = device;
emit(DeviceControlSuccess(code: control.code));
} else {
emit(DeviceControlError('Failed to toggle curtain.'));
}
} catch (error) {
emit(DeviceControlError(error.toString()));
}
}
Future<void> changeGarageSwitch(
DeviceControlModel control, String deviceUuid) async {
emit(SwitchControlLoading(code: control.code));
try {
final deviceIndex = allDevices.indexWhere((d) => d.uuid == deviceUuid);
if (deviceIndex == -1) {
throw Exception('Device not found');
}
final device = allDevices[deviceIndex];
final isOpen = control.value == "open";
final newValue = isOpen ? 0 : 100;
final response = await DevicesAPI.deviceBatchController(
code: 'percent_control',
devicesUuid: [deviceUuid],
value: newValue,
);
if (response['success'] == true) {
final statusIndex =
device.status.indexWhere((s) => s.code == 'percent_control');
if (statusIndex != -1) {
device.status[statusIndex].value = newValue;
}
allDevices[deviceIndex] = device;
emit(DeviceControlSuccess(code: control.code));
} else {
emit(DeviceControlError('Failed to toggle curtain.'));
}
} catch (error) {
emit(DeviceControlError(error.toString()));
}
}
} }
enum LightMode { enum LightMode {

View File

@ -34,6 +34,7 @@ class GetDeviceStatusError extends DevicesState {
} }
class GetDevicesLoading extends DevicesState {} class GetDevicesLoading extends DevicesState {}
class RoomLoading extends DevicesState {}
class GetDevicesSuccess extends DevicesState { class GetDevicesSuccess extends DevicesState {
GetDevicesSuccess(this.devices); GetDevicesSuccess(this.devices);
@ -55,10 +56,16 @@ class DeviceSwitchChanged extends DevicesState {}
class DeviceSelected extends DevicesState {} class DeviceSelected extends DevicesState {}
// Device Control // Device Control
class DeviceControlLoading extends DevicesState { // class DeviceControlLoading extends DevicesState {
final String? code; // final String? code;
DeviceControlLoading({this.code}); // DeviceControlLoading({this.code});
// }
class SwitchControlLoading extends DevicesState {
final String? code;
final String? deviceId;
SwitchControlLoading({this.deviceId, this.code});
} }
class DeviceControlSuccess extends DevicesState { class DeviceControlSuccess extends DevicesState {

View File

@ -21,13 +21,14 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
on<ToggleClosingReminderEvent>(_toggleClosingReminder); on<ToggleClosingReminderEvent>(_toggleClosingReminder);
on<ToggleDoorAlarmEvent>(_toggleDoorAlarm); on<ToggleDoorAlarmEvent>(_toggleDoorAlarm);
} }
Timer? _timer;
bool lowBattery = false; bool lowBattery = false;
bool closingReminder = false; bool closingReminder = false;
bool doorAlarm = false; bool doorAlarm = false;
DoorSensorModel deviceStatus = DoorSensorModel(doorContactState: false, batteryPercentage: 0); DoorSensorModel deviceStatus =
DoorSensorModel(doorContactState: false, batteryPercentage: 0);
void _fetchStatus(DoorSensorInitial event, Emitter<DoorSensorState> emit) async { void _fetchStatus(
DoorSensorInitial event, Emitter<DoorSensorState> emit) async {
emit(DoorSensorLoadingState()); emit(DoorSensorLoadingState());
try { try {
var response = await DevicesAPI.getDeviceStatus(DSId); var response = await DevicesAPI.getDeviceStatus(DSId);
@ -40,7 +41,7 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
); );
emit(UpdateState(doorSensor: deviceStatus)); emit(UpdateState(doorSensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500)); Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges(); _listenToChanges();
} catch (e) { } catch (e) {
emit(DoorSensorFailedState(errorMessage: e.toString())); emit(DoorSensorFailedState(errorMessage: e.toString()));
return; return;
@ -48,7 +49,8 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
} }
// Toggle functions for each switch // Toggle functions for each switch
void _toggleLowBattery(ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async { void _toggleLowBattery(
ToggleLowBatteryEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
lowBattery = event.isLowBatteryEnabled; lowBattery = event.isLowBatteryEnabled;
@ -89,7 +91,8 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
} }
} }
void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter<DoorSensorState> emit) async { void _toggleDoorAlarm(
ToggleDoorAlarmEvent event, Emitter<DoorSensorState> emit) async {
emit(LoadingNewSate(doorSensor: deviceStatus)); emit(LoadingNewSate(doorSensor: deviceStatus));
try { try {
doorAlarm = event.isDoorAlarmEnabled; doorAlarm = event.isDoorAlarmEnabled;
@ -108,9 +111,11 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
} }
} }
DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []); DeviceReport recordGroups =
DeviceReport(startTime: '0', endTime: '0', data: []);
Future<void> fetchLogsForLastMonth(ReportLogsInitial event, Emitter<DoorSensorState> emit) async { Future<void> fetchLogsForLastMonth(
ReportLogsInitial event, Emitter<DoorSensorState> emit) async {
DateTime now = DateTime.now(); DateTime now = DateTime.now();
DateTime lastMonth = DateTime(now.year, now.month - 1, now.day); DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
@ -133,22 +138,27 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
} }
} }
_listenToChanges() { // real-time database
Timer? _timer;
StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$DSId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$DSId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { _streamSubscription = stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
} }
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: true)); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = DoorSensorModel.fromJson(statusList); deviceStatus = DoorSensorModel.fromJson(statusList);
if (!isClosed) { if (!isClosed) {
add( add(
@ -158,4 +168,11 @@ class DoorSensorBloc extends Bloc<DoorSensorEvent, DoorSensorState> {
}); });
} catch (_) {} } catch (_) {}
} }
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
} }

View File

@ -1,6 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_event.dart'; import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_event.dart';
import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_state.dart'; import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart';
@ -14,6 +16,7 @@ import 'package:syncrow_app/features/devices/model/subspace_model.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart'; import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/scene_api.dart'; import 'package:syncrow_app/services/api/scene_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> { class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
@ -230,6 +233,7 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
deviceStatus = FourSceneModelState.fromJson( deviceStatus = FourSceneModelState.fromJson(
statusModelList, statusModelList,
); );
// _listenToChanges();
add(const FourSceneSwitchInitial()); add(const FourSceneSwitchInitial());
} catch (e) { } catch (e) {
emit(FourSceneFailedState(errorMessage: e.toString())); emit(FourSceneFailedState(errorMessage: e.toString()));
@ -299,9 +303,11 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
LoadScenes event, Emitter<FourSceneState> emit) async { LoadScenes event, Emitter<FourSceneState> emit) async {
emit(FourSceneLoadingState()); emit(FourSceneLoadingState());
try { try {
Project? project = HomeCubit.getInstance().project;
if (event.unitId.isNotEmpty) { if (event.unitId.isNotEmpty) {
allScenes = await SceneApi.getScenesByUnitId( allScenes = await SceneApi.getScenesByUnitId(
event.unitId, event.unit.community.uuid, event.unitId, event.unit.community.uuid, project?.uuid ?? TempConst.projectIdDev,
showInDevice: event.showInDevice); showInDevice: event.showInDevice);
filteredScenes = allScenes; filteredScenes = allScenes;
@ -327,4 +333,33 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
}).toList(); }).toList();
emit(SearchResultsState()); emit(SearchResultsState());
} }
// Real-time database
// Timer? _timer;
// _listenToChanges() {
// try {
// DatabaseReference ref =
// FirebaseDatabase.instance.ref('device-status/$fourSceneId');
// Stream<DatabaseEvent> stream = ref.onValue;
// stream.listen((DatabaseEvent event) async {
// if (_timer != null) {
// await Future.delayed(const Duration(seconds: 2));
// }
// Map<dynamic, dynamic> usersMap =
// event.snapshot.value as Map<dynamic, dynamic>;
// List<StatusModel> statusList = [];
// usersMap['status'].forEach((element) {
// statusList.add(StatusModel(code: element['code'], value: true));
// });
// deviceStatus = FourSceneModelState.fromJson(statusList);
// // if (!isClosed) {
// // add(
// // DoorSensorSwitch(switchD: deviceStatus.doorContactState),
// // );
// // }
// });
// } catch (_) {}
// }
} }

View File

@ -42,7 +42,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch); on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<ToggleAlarmEvent>(_toggleAlarmEvent); on<ToggleAlarmEvent>(_toggleAlarmEvent);
on<DeleteScheduleEvent>(deleteSchedule); on<DeleteScheduleEvent>(deleteSchedule);
//_toggleAlarmEvent
on<UpdateStateEvent>(_updateState);
} }
void _onClose(OnClose event, Emitter<GarageDoorSensorState> emit) { void _onClose(OnClose event, Emitter<GarageDoorSensorState> emit) {
_timer?.cancel(); _timer?.cancel();
@ -81,7 +82,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
toggleDoor = deviceStatus.switch1; toggleDoor = deviceStatus.switch1;
emit(UpdateState(garageSensor: deviceStatus)); emit(UpdateState(garageSensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500)); Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges(); _listenToChanges();
} catch (e) { } catch (e) {
emit(GarageDoorFailedState(errorMessage: e.toString())); emit(GarageDoorFailedState(errorMessage: e.toString()));
return; return;
@ -180,33 +181,59 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
} }
} }
_listenToChanges() { // Real-time db
StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges() {
try { try {
_streamSubscription?.cancel();
DatabaseReference ref = DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$GDId'); FirebaseDatabase.instance.ref('device-status/$GDId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { _streamSubscription = stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 1));
} }
Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: true));
});
deviceStatus = GarageDoorModel.fromJson(statusList); if (event.snapshot.value != null) {
if (!isClosed) { Map<dynamic, dynamic> usersMap =
// add( event.snapshot.value as Map<dynamic, dynamic>;
// DoorSensorSwitch(switchD: deviceStatus.doorContactState), List<StatusModel> statusList = [];
// );
usersMap['status'].forEach((element) {
statusList.add(
StatusModel(code: element['code'], value: element['value']));
});
deviceStatus.tr_timecon = statusList
.firstWhere((status) => status.code == "tr_timecon",
orElse: () => StatusModel(code: "tr_timecon", value: 0))
.value as int;
deviceStatus.switch1 = statusList
.firstWhere((status) => status.code == "switch_1",
orElse: () => StatusModel(code: "switch_1", value: false))
.value as bool;
secondSelected = deviceStatus.tr_timecon;
toggleDoor = deviceStatus.switch1;
add(UpdateStateEvent());
} }
}); });
} catch (_) {} } catch (_) {}
} }
Future<void> _updateState(
UpdateStateEvent event, Emitter<GarageDoorSensorState> emit) async {
emit(GarageDoorLoadingState());
emit(UpdateState(garageSensor: deviceStatus));
}
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
List<Map<String, String>> days = [ List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"}, {"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"}, {"day": "Mon", "key": "Mon"},

View File

@ -109,6 +109,8 @@ class GetScheduleEvent extends GarageDoorEvent {}
class ScheduleSaveapp extends GarageDoorEvent {} class ScheduleSaveapp extends GarageDoorEvent {}
class UpdateStateEvent extends GarageDoorEvent {}
class ToggleScheduleEvent extends GarageDoorEvent { class ToggleScheduleEvent extends GarageDoorEvent {
final String id; final String id;
final bool toggle; final bool toggle;

View File

@ -26,7 +26,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
bool oneGangGroup = false; bool oneGangGroup = false;
List<DeviceModel> devicesList = []; List<DeviceModel> devicesList = [];
OneGangBloc({required this.oneGangId, required this.switchCode}) : super(InitialState()) { OneGangBloc({required this.oneGangId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchOneGangStatus); on<InitialEvent>(_fetchOneGangStatus);
on<OneGangUpdated>(_oneGangUpdated); on<OneGangUpdated>(_oneGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch); on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -49,7 +50,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
on<GroupAllOffEvent>(_groupAllOff); on<GroupAllOffEvent>(_groupAllOff);
} }
void _fetchOneGangStatus(InitialEvent event, Emitter<OneGangState> emit) async { void _fetchOneGangStatus(
InitialEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(oneGangId); var response = await DevicesAPI.getDeviceStatus(oneGangId);
@ -59,42 +61,51 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
} }
deviceStatus = OneGangModel.fromJson(statusModelList); deviceStatus = OneGangModel.fromJson(statusModelList);
emit(UpdateState(oneGangModel: deviceStatus)); emit(UpdateState(oneGangModel: deviceStatus));
// _listenToChanges(); _listenToChanges(oneGangId);
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
_listenToChanges() { // Real-time db
StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges(String id) {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$oneGangId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$id');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { _streamSubscription = stream.listen((DatabaseEvent event) {
if (_timer != null) { Map<dynamic, dynamic> usersMap =
await Future.delayed(const Duration(seconds: 2)); event.snapshot.value as Map<dynamic, dynamic>;
}
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = OneGangModel.fromJson(statusList); deviceStatus = OneGangModel.fromJson(statusList);
if (!isClosed) { add(OneGangUpdated());
add(OneGangUpdated());
}
}); });
} catch (_) {} } catch (_) {}
} }
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_oneGangUpdated(OneGangUpdated event, Emitter<OneGangState> emit) { _oneGangUpdated(OneGangUpdated event, Emitter<OneGangState> emit) {
emit(LoadingInitialState());
emit(UpdateState(oneGangModel: deviceStatus)); emit(UpdateState(oneGangModel: deviceStatus));
} }
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<OneGangState> emit) async { void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus)); emit(LoadingNewSate(oneGangModel: deviceStatus));
try { try {
deviceStatus.firstSwitch = !event.value; deviceStatus.firstSwitch = !event.value;
@ -119,17 +130,20 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
} }
} }
void _changeSliding(ChangeSlidingSegment event, Emitter<OneGangState> emit) async { void _changeSliding(
ChangeSlidingSegment event, Emitter<OneGangState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value)); emit(ChangeSlidingSegmentState(value: event.value));
} }
void _setCounterValue(SetCounterValue event, Emitter<OneGangState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus)); emit(LoadingNewSate(oneGangModel: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: oneGangId, code: event.deviceCode, value: seconds), DeviceControlModel(
deviceId: oneGangId, code: event.deviceCode, value: seconds),
oneGangId); oneGangId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
@ -152,7 +166,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<OneGangState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(oneGangId); var response = await DevicesAPI.getDeviceStatus(oneGangId);
@ -241,7 +256,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
deviceId: oneGangId, deviceId: oneGangId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState()); emit(InitialState());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -252,12 +268,13 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleChange(ToggleScheduleEvent event, Emitter<OneGangState> emit) async { Future toggleChange(
ToggleScheduleEvent event, Emitter<OneGangState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -276,7 +293,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<OneGangState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<OneGangState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -296,7 +314,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
} }
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<OneGangState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();
@ -325,7 +344,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
int selectedTabIndex = 0; int selectedTabIndex = 0;
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<OneGangState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<OneGangState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
@ -334,7 +354,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
List<GroupOneGangModel> groupOneGangList = []; List<GroupOneGangModel> groupOneGangList = [];
bool allSwitchesOn = true; bool allSwitchesOn = true;
void _fetchOneGangWizardStatus(InitialWizardEvent event, Emitter<OneGangState> emit) async { void _fetchOneGangWizardStatus(
InitialWizardEvent event, Emitter<OneGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
devicesList = []; devicesList = [];
@ -344,7 +365,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '1G'); HomeCubit.getInstance().selectedSpace?.id ?? '', '1G');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -365,15 +387,16 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
return true; return true;
}); });
} }
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: allSwitchesOn)); emit(UpdateGroupState(
oneGangList: groupOneGangList, allSwitches: allSwitchesOn));
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
void _changeFirstWizardSwitch( void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
ChangeFirstWizardSwitchStatusEvent event, Emitter<OneGangState> emit) async { Emitter<OneGangState> emit) async {
emit(LoadingNewSate(oneGangModel: deviceStatus)); emit(LoadingNewSate(oneGangModel: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -386,7 +409,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
} }
}); });
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
oneGangList: groupOneGangList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -414,7 +438,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: true)); emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: true));
// Get a list of all device IDs // Get a list of all device IDs
List<String> allDeviceIds = groupOneGangList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1 // First call for switch_1
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
@ -446,7 +471,8 @@ class OneGangBloc extends Bloc<OneGangEvent, OneGangState> {
emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: false)); emit(UpdateGroupState(oneGangList: groupOneGangList, allSwitches: false));
// Get a list of all device IDs // Get a list of all device IDs
List<String> allDeviceIds = groupOneGangList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupOneGangList.map((device) => device.deviceId).toList();
// First call for switch_1 // First call for switch_1
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(

View File

@ -30,7 +30,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
bool oneTouchGroup = false; bool oneTouchGroup = false;
List<DeviceModel> devicesList = []; List<DeviceModel> devicesList = [];
OneTouchBloc({required this.oneTouchId, required this.switchCode}) : super(InitialState()) { OneTouchBloc({required this.oneTouchId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchOneTouchStatus); on<InitialEvent>(_fetchOneTouchStatus);
on<OneTouchUpdated>(_oneTouchUpdated); on<OneTouchUpdated>(_oneTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch); on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -53,7 +54,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
on<ChangeStatusEvent>(_changeStatus); on<ChangeStatusEvent>(_changeStatus);
} }
void _fetchOneTouchStatus(InitialEvent event, Emitter<OneTouchState> emit) async { void _fetchOneTouchStatus(
InitialEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(oneTouchId); var response = await DevicesAPI.getDeviceStatus(oneTouchId);
@ -62,43 +64,59 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
} }
deviceStatus = OneTouchModel.fromJson(statusModelList); deviceStatus = OneTouchModel.fromJson(statusModelList);
_listenToChanges(oneTouchId);
emit(UpdateState(oneTouchModel: deviceStatus)); emit(UpdateState(oneTouchModel: deviceStatus));
// _listenToChanges();
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
_listenToChanges() { StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges(String id) {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$oneTouchId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$id');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { _streamSubscription = stream.listen((DatabaseEvent event) {
if (_timer != null) { if (event.snapshot.value != null) {
await Future.delayed(const Duration(seconds: 2)); Map<dynamic, dynamic> usersMap =
} event.snapshot.value as Map<dynamic, dynamic>;
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; List<StatusModel> statusList = [];
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList.add(
}); StatusModel(code: element['code'], value: element['value']));
});
var switchStatus = statusList.firstWhere(
(status) => status.code == "switch_1",
orElse: () => StatusModel(code: "switch_1", value: false));
deviceStatus = OneTouchModel.fromJson(statusList); deviceStatus.firstSwitch = switchStatus.value as bool;
if (!isClosed) {
add(OneTouchUpdated()); add(OneTouchUpdated());
} }
}); });
} catch (_) {} } catch (_) {
}
}
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
} }
_oneTouchUpdated(OneTouchUpdated event, Emitter<OneTouchState> emit) { _oneTouchUpdated(OneTouchUpdated event, Emitter<OneTouchState> emit) {
emit(LoadingNewSate(oneTouchModel: deviceStatus));
emit(UpdateState(oneTouchModel: deviceStatus)); emit(UpdateState(oneTouchModel: deviceStatus));
} }
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<OneTouchState> emit) async { void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus)); emit(LoadingNewSate(oneTouchModel: deviceStatus));
try { try {
deviceStatus.firstSwitch = !event.value; deviceStatus.firstSwitch = !event.value;
@ -123,17 +141,20 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
} }
} }
void _changeSliding(ChangeSlidingSegment event, Emitter<OneTouchState> emit) async { void _changeSliding(
ChangeSlidingSegment event, Emitter<OneTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value)); emit(ChangeSlidingSegmentState(value: event.value));
} }
void _setCounterValue(SetCounterValue event, Emitter<OneTouchState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus)); emit(LoadingNewSate(oneTouchModel: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: oneTouchId, code: event.deviceCode, value: seconds), DeviceControlModel(
deviceId: oneTouchId, code: event.deviceCode, value: seconds),
oneTouchId); oneTouchId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
@ -156,7 +177,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<OneTouchState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(oneTouchId); var response = await DevicesAPI.getDeviceStatus(oneTouchId);
@ -245,7 +267,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
deviceId: oneTouchId, deviceId: oneTouchId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState()); emit(InitialState());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -256,12 +279,13 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleChange(ToggleScheduleEvent event, Emitter<OneTouchState> emit) async { Future toggleChange(
ToggleScheduleEvent event, Emitter<OneTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -280,7 +304,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<OneTouchState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<OneTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -300,7 +325,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
} }
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<OneTouchState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<OneTouchState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();
@ -329,7 +355,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
int selectedTabIndex = 0; int selectedTabIndex = 0;
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<OneTouchState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<OneTouchState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
@ -338,7 +365,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
List<GroupOneTouchModel> groupOneTouchList = []; List<GroupOneTouchModel> groupOneTouchList = [];
bool allSwitchesOn = true; bool allSwitchesOn = true;
void _fetchOneTouchWizardStatus(InitialWizardEvent event, Emitter<OneTouchState> emit) async { void _fetchOneTouchWizardStatus(
InitialWizardEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
devicesList = []; devicesList = [];
@ -348,7 +376,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '1GT'); HomeCubit.getInstance().selectedSpace?.id ?? '', '1GT');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -369,15 +398,16 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
return true; return true;
}); });
} }
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: allSwitchesOn)); emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: allSwitchesOn));
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
void _changeFirstWizardSwitch( void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
ChangeFirstWizardSwitchStatusEvent event, Emitter<OneTouchState> emit) async { Emitter<OneTouchState> emit) async {
emit(LoadingNewSate(oneTouchModel: deviceStatus)); emit(LoadingNewSate(oneTouchModel: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -395,7 +425,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
value: !event.value, value: !event.value,
); );
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: allSwitchesValue));
if (response['success']) { if (response['success']) {
add(InitialEvent(groupScreen: oneTouchGroup)); add(InitialEvent(groupScreen: oneTouchGroup));
} }
@ -413,10 +444,12 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
} }
// Emit the state with updated values // Emit the state with updated values
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: true)); emit(
UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: true));
// Get a list of all device IDs // Get a list of all device IDs
List<String> allDeviceIds = groupOneTouchList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupOneTouchList.map((device) => device.deviceId).toList();
// First call for switch_1 // First call for switch_1
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
@ -445,10 +478,12 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
} }
// Emit the state with updated values // Emit the state with updated values
emit(UpdateGroupState(oneTouchList: groupOneTouchList, allSwitches: false)); emit(UpdateGroupState(
oneTouchList: groupOneTouchList, allSwitches: false));
// Get a list of all device IDs // Get a list of all device IDs
List<String> allDeviceIds = groupOneTouchList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupOneTouchList.map((device) => device.deviceId).toList();
// First call for switch_1 // First call for switch_1
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
@ -472,7 +507,8 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
String statusSelected = ''; String statusSelected = '';
String optionSelected = ''; String optionSelected = '';
Future<void> _changeStatus(ChangeStatusEvent event, Emitter<OneTouchState> emit) async { Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
@ -497,7 +533,10 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
final selectedControl = controlMap[optionSelected]?[statusSelected]; final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) { if (selectedControl != null) {
await DevicesAPI.controlDevice( await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: oneTouchId, code: optionSelected, value: selectedControl), DeviceControlModel(
deviceId: oneTouchId,
code: optionSelected,
value: selectedControl),
oneTouchId, oneTouchId,
); );
} else { } else {

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -37,7 +38,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
on<SelectTimeEvent>(selectTimeOfLinePassword); on<SelectTimeEvent>(selectTimeOfLinePassword);
on<SelectTimeOnlinePasswordEvent>(selectTimeOnlinePassword); on<SelectTimeOnlinePasswordEvent>(selectTimeOnlinePassword);
on<DeletePasswordEvent>(deletePassword); on<DeletePasswordEvent>(deletePassword);
on<GenerateAndSavePasswordTimeLimitEvent>(generateAndSavePasswordTimeLimited); on<GenerateAndSavePasswordTimeLimitEvent>(
generateAndSavePasswordTimeLimited);
on<GenerateAndSavePasswordOneTimeEvent>(generateAndSavePasswordOneTime); on<GenerateAndSavePasswordOneTimeEvent>(generateAndSavePasswordOneTime);
on<ToggleDaySelectionEvent>(toggleDaySelection); on<ToggleDaySelectionEvent>(toggleDaySelection);
on<RenamePasswordEvent>(_renamePassword); on<RenamePasswordEvent>(_renamePassword);
@ -59,7 +61,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
List<OfflinePasswordModel>? oneTimePasswords = []; List<OfflinePasswordModel>? oneTimePasswords = [];
List<OfflinePasswordModel>? timeLimitPasswords = []; List<OfflinePasswordModel>? timeLimitPasswords = [];
Future generate7DigitNumber(GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async { Future generate7DigitNumber(
GeneratePasswordEvent event, Emitter<SmartDoorState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
passwordController.clear(); passwordController.clear();
Random random = Random(); Random random = Random();
@ -71,7 +74,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
Future generateAndSavePasswordOneTime( Future generateAndSavePasswordOneTime(
GenerateAndSavePasswordOneTimeEvent event, Emitter<SmartDoorState> emit) async { GenerateAndSavePasswordOneTimeEvent event,
Emitter<SmartDoorState> emit) async {
try { try {
if (isSavingPassword) return; if (isSavingPassword) return;
isSavingPassword = true; isSavingPassword = true;
@ -92,7 +96,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
} }
void _fetchSmartDoorStatus(InitialEvent event, Emitter<SmartDoorState> emit) async { void _fetchSmartDoorStatus(
InitialEvent event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
var response = await DevicesAPI.getDeviceStatus(deviceId); var response = await DevicesAPI.getDeviceStatus(deviceId);
@ -102,42 +107,63 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
deviceStatus = SmartDoorModel.fromJson(statusModelList); deviceStatus = SmartDoorModel.fromJson(statusModelList);
emit(UpdateState(smartDoorModel: deviceStatus)); emit(UpdateState(smartDoorModel: deviceStatus));
// _listenToChanges(); _listenToChanges();
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
return; return;
} }
} }
_listenToChanges() { StreamSubscription<DatabaseEvent>? _streamSubscription;
Timer? _timer;
void _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) { _streamSubscription = stream.listen((DatabaseEvent event) async {
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = SmartDoorModel.fromJson(statusList); deviceStatus = SmartDoorModel.fromJson(statusList);
add(DoorLockUpdated()); if (!isClosed) {
add(DoorLockUpdated());
}
}); });
} catch (_) {} } catch (_) {}
} }
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_doorLockUpdated(DoorLockUpdated event, Emitter<SmartDoorState> emit) { _doorLockUpdated(DoorLockUpdated event, Emitter<SmartDoorState> emit) {
unlockRequest = deviceStatus.unlockRequest; unlockRequest = deviceStatus.unlockRequest;
emit(UpdateState(smartDoorModel: deviceStatus)); emit(UpdateState(smartDoorModel: deviceStatus));
} }
void _renamePassword(RenamePasswordEvent event, Emitter<SmartDoorState> emit) async { void _renamePassword(
RenamePasswordEvent event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
await DevicesAPI.renamePass( await DevicesAPI.renamePass(
name: passwordNameController.text, doorLockUuid: deviceId, passwordId: passwordId); name: passwordNameController.text,
doorLockUuid: deviceId,
passwordId: passwordId);
add(InitialOneTimePassword()); add(InitialOneTimePassword());
add(InitialTimeLimitPassword()); add(InitialTimeLimitPassword());
emit(UpdateState(smartDoorModel: deviceStatus)); emit(UpdateState(smartDoorModel: deviceStatus));
@ -147,46 +173,58 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
} }
void getTemporaryPasswords(InitialPasswordsPage event, Emitter<SmartDoorState> emit) async { void getTemporaryPasswords(
InitialPasswordsPage event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
var response = await DevicesAPI.getTemporaryPasswords( var response = await DevicesAPI.getTemporaryPasswords(
deviceId, deviceId,
); );
if (response is List) { if (response is List) {
temporaryPasswords = response.map((item) => TemporaryPassword.fromJson(item)).toList();
} else if (response is Map && response.containsKey('data')) {
temporaryPasswords = temporaryPasswords =
(response['data'] as List).map((item) => TemporaryPassword.fromJson(item)).toList(); 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();
} }
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!)); emit(TemporaryPasswordsLoadedState(
temporaryPassword: temporaryPasswords!));
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
} }
} }
void getOneTimePasswords(InitialOneTimePassword event, Emitter<SmartDoorState> emit) async { void getOneTimePasswords(
InitialOneTimePassword event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
var response = await DevicesAPI.getOneTimePasswords(deviceId); var response = await DevicesAPI.getOneTimePasswords(deviceId);
if (response is List) { if (response is List) {
oneTimePasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList(); oneTimePasswords = response
.map((item) => OfflinePasswordModel.fromJson(item))
.toList();
} }
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!)); emit(TemporaryPasswordsLoadedState(
temporaryPassword: temporaryPasswords!));
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
} }
} }
void getTimeLimitPasswords(InitialTimeLimitPassword event, Emitter<SmartDoorState> emit) async { void getTimeLimitPasswords(
InitialTimeLimitPassword event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
var response = await DevicesAPI.getTimeLimitPasswords(deviceId); var response = await DevicesAPI.getTimeLimitPasswords(deviceId);
if (response is List) { if (response is List) {
timeLimitPasswords = response.map((item) => OfflinePasswordModel.fromJson(item)).toList(); timeLimitPasswords = response
.map((item) => OfflinePasswordModel.fromJson(item))
.toList();
} }
emit(TemporaryPasswordsLoadedState(temporaryPassword: temporaryPasswords!)); emit(TemporaryPasswordsLoadedState(
temporaryPassword: temporaryPasswords!));
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
} }
@ -207,7 +245,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
return repeat; return repeat;
} }
bool setStartEndTime(SetStartEndTimeEvent event, Emitter<SmartDoorState> emit) { bool setStartEndTime(
SetStartEndTimeEvent event, Emitter<SmartDoorState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
isStartEndTime = event.val; isStartEndTime = event.val;
emit(IsStartEndState(isStartEndTime: isStartEndTime)); emit(IsStartEndState(isStartEndTime: isStartEndTime));
@ -230,7 +269,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
emit(UpdateState(smartDoorModel: deviceStatus)); emit(UpdateState(smartDoorModel: deviceStatus));
} }
Future<void> selectTimeOfLinePassword(SelectTimeEvent event, Emitter<SmartDoorState> emit) async { Future<void> selectTimeOfLinePassword(
SelectTimeEvent event, Emitter<SmartDoorState> emit) async {
emit(ChangeTimeState()); emit(ChangeTimeState());
final DateTime? picked = await showDatePicker( final DateTime? picked = await showDatePicker(
context: event.context, context: event.context,
@ -260,20 +300,27 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
).millisecondsSinceEpoch ~/ ).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds 1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) { if (event.isEffective) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) { if (expirationTimeTimeStamp != null &&
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
} else { } else {
effectiveTime = effectiveTime = selectedDateTime
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds .toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp; effectiveTimeTimeStamp = selectedTimestamp;
} }
} else { } else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar( CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.'); 'Expiration Time cannot be earlier than Effective Time.');
} else { } else {
expirationTime = expirationTime = selectedDateTime
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds .toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp; expirationTimeTimeStamp = selectedTimestamp;
} }
} }
@ -329,20 +376,27 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
).millisecondsSinceEpoch ~/ ).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds 1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) { if (event.isEffective) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) { if (expirationTimeTimeStamp != null &&
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
} else { } else {
effectiveTime = effectiveTime = selectedDateTime
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds .toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp; effectiveTimeTimeStamp = selectedTimestamp;
} }
} else { } else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar( CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.'); 'Expiration Time cannot be earlier than Effective Time.');
} else { } else {
expirationTime = expirationTime = selectedDateTime
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds .toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp; expirationTimeTimeStamp = selectedTimestamp;
} }
} }
@ -351,7 +405,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
} }
Future<void> savePassword(SavePasswordEvent event, Emitter<SmartDoorState> emit) async { Future<void> savePassword(
SavePasswordEvent event, Emitter<SmartDoorState> emit) async {
if (_validateInputs() || isSavingPassword) return; if (_validateInputs() || isSavingPassword) return;
try { try {
isSavingPassword = true; isSavingPassword = true;
@ -381,7 +436,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
Future<void> generateAndSavePasswordTimeLimited( Future<void> generateAndSavePasswordTimeLimited(
GenerateAndSavePasswordTimeLimitEvent event, Emitter<SmartDoorState> emit) async { GenerateAndSavePasswordTimeLimitEvent event,
Emitter<SmartDoorState> emit) async {
if (timeLimitValidate() || isSavingPassword) return; if (timeLimitValidate() || isSavingPassword) return;
try { try {
isSavingPassword = true; isSavingPassword = true;
@ -407,10 +463,12 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
} }
Future<void> deletePassword(DeletePasswordEvent event, Emitter<SmartDoorState> emit) async { Future<void> deletePassword(
DeletePasswordEvent event, Emitter<SmartDoorState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
await DevicesAPI.deletePassword(deviceId: deviceId, passwordId: event.passwordId) await DevicesAPI.deletePassword(
deviceId: deviceId, passwordId: event.passwordId)
.then((value) async { .then((value) async {
add(InitialPasswordsPage()); add(InitialPasswordsPage());
}); });
@ -445,7 +503,8 @@ class SmartDoorBloc extends Bloc<SmartDoorEvent, SmartDoorState> {
} }
if (repeat == true && (endTime == null || startTime == null)) { if (repeat == true && (endTime == null || startTime == null)) {
CustomSnackBar.displaySnackBar('Start Time and End time and the days required '); CustomSnackBar.displaySnackBar(
'Start Time and End time and the days required ');
return true; return true;
} }
return false; return false;

View File

@ -1,10 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/app_layout/model/community_model.dart'; import 'package:syncrow_app/features/app_layout/model/community_model.dart';
import 'package:syncrow_app/features/app_layout/model/space_model.dart'; import 'package:syncrow_app/features/app_layout/model/space_model.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart'; import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart'; import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart';
@ -19,6 +21,7 @@ import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart'; import 'package:syncrow_app/services/api/home_management_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class SosBloc extends Bloc<SosEvent, SosState> { class SosBloc extends Bloc<SosEvent, SosState> {
@ -171,6 +174,7 @@ class SosBloc extends Bloc<SosEvent, SosState> {
); );
emit(UpdateState(sensor: deviceStatus)); emit(UpdateState(sensor: deviceStatus));
Future.delayed(const Duration(milliseconds: 500)); Future.delayed(const Duration(milliseconds: 500));
// _listenToChanges();
} catch (e) { } catch (e) {
emit(SosFailedState(errorMessage: e.toString())); emit(SosFailedState(errorMessage: e.toString()));
return; return;
@ -184,8 +188,12 @@ class SosBloc extends Bloc<SosEvent, SosState> {
FetchRoomsEvent event, Emitter<SosState> emit) async { FetchRoomsEvent event, Emitter<SosState> emit) async {
try { try {
emit(SosLoadingState()); emit(SosLoadingState());
Project? project = HomeCubit.getInstance().project;
roomsList = await SpacesAPI.getSubSpaceBySpaceId( roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id); event.unit.community.uuid,
event.unit.id,
project?.uuid ?? TempConst.projectIdDev);
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList)); emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
} catch (e) { } catch (e) {
emit(const SosFailedState(errorMessage: 'Something went wrong')); emit(const SosFailedState(errorMessage: 'Something went wrong'));
@ -223,13 +231,19 @@ class SosBloc extends Bloc<SosEvent, SosState> {
void _assignDevice(AssignRoomEvent event, Emitter<SosState> emit) async { void _assignDevice(AssignRoomEvent event, Emitter<SosState> emit) async {
try { try {
emit(SosLoadingState()); emit(SosLoadingState());
Project? project = HomeCubit.getInstance().project;
await HomeManagementAPI.assignDeviceToRoom( await HomeManagementAPI.assignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, sosId); event.unit.community.uuid,
event.unit.id,
event.roomId,
sosId,
project?.uuid ?? TempConst.projectIdDev);
final devicesList = await DevicesAPI.getDevicesByRoomId( final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid, communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id, spaceUuid: event.unit.id,
roomId: event.roomId); roomId: event.roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
List<String> allDevicesIds = []; List<String> allDevicesIds = [];
@ -249,13 +263,16 @@ class SosBloc extends Bloc<SosEvent, SosState> {
void _unassignDevice(UnassignRoomEvent event, Emitter<SosState> emit) async { void _unassignDevice(UnassignRoomEvent event, Emitter<SosState> emit) async {
try { try {
Map<String, bool> roomDevicesId = {}; Map<String, bool> roomDevicesId = {};
Project? project = HomeCubit.getInstance().project;
emit(SosLoadingState()); emit(SosLoadingState());
await HomeManagementAPI.unAssignDeviceToRoom( await HomeManagementAPI.unAssignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, sosId); event.unit.community.uuid, event.unit.id, event.roomId, sosId, project?.uuid ?? TempConst.projectIdDev);
final devicesList = await DevicesAPI.getDevicesByRoomId( final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid, communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id, spaceUuid: event.unit.id,
roomId: event.roomId); roomId: event.roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
List<String> allDevicesIds = []; List<String> allDevicesIds = [];
@ -419,4 +436,39 @@ class SosBloc extends Bloc<SosEvent, SosState> {
emit(SosFailedState(errorMessage: e.toString())); emit(SosFailedState(errorMessage: e.toString()));
} }
} }
//real-time db
// StreamSubscription<DatabaseEvent>? _streamSubscription;
// Timer? _timer;
// void _listenToChanges() {
// try {
// _streamSubscription?.cancel();
// DatabaseReference ref =
// FirebaseDatabase.instance.ref('device-status/$sosId');
// Stream<DatabaseEvent> stream = ref.onValue;
// _streamSubscription = 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 = SosModel.fromJson(statusList);
// });
// } catch (_) {}
// }
// @override
// Future<void> close() async {
// _streamSubscription?.cancel();
// _streamSubscription = null;
// return super.close();
// }
} }

View File

@ -31,7 +31,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
List<GroupThreeGangModel> groupThreeGangList = []; List<GroupThreeGangModel> groupThreeGangList = [];
bool allSwitchesOn = true; bool allSwitchesOn = true;
ThreeGangBloc({required this.threeGangId, required this.switchCode}) : super(InitialState()) { ThreeGangBloc({required this.threeGangId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchThreeGangStatus); on<InitialEvent>(_fetchThreeGangStatus);
on<ThreeGangUpdated>(_threeGangUpdated); on<ThreeGangUpdated>(_threeGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch); on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -57,7 +58,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
on<ToggleCreateScheduleEvent>(toggleCreateSchedule); on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
} }
void _fetchThreeGangStatus(InitialEvent event, Emitter<ThreeGangState> emit) async { void _fetchThreeGangStatus(
InitialEvent event, Emitter<ThreeGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
threeGangGroup = event.groupScreen; threeGangGroup = event.groupScreen;
@ -69,7 +71,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '3G'); HomeCubit.getInstance().selectedSpace?.id ?? '', '3G');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -86,13 +89,16 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
if (groupThreeGangList.isNotEmpty) { if (groupThreeGangList.isNotEmpty) {
groupThreeGangList.firstWhere((element) { groupThreeGangList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesOn = false; allSwitchesOn = false;
} }
return true; return true;
}); });
} }
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesOn)); emit(UpdateGroupState(
threeGangList: groupThreeGangList, allSwitches: allSwitchesOn));
} else { } else {
var response = await DevicesAPI.getDeviceStatus(threeGangId); var response = await DevicesAPI.getDeviceStatus(threeGangId);
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
@ -101,7 +107,7 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
deviceStatus = ThreeGangModel.fromJson(statusModelList); deviceStatus = ThreeGangModel.fromJson(statusModelList);
emit(UpdateState(threeGangModel: deviceStatus)); emit(UpdateState(threeGangModel: deviceStatus));
// _listenToChanges(); _listenToChanges();
} }
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
@ -109,22 +115,26 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
} }
_listenToChanges() { StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$threeGangId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$threeGangId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { _streamSubscription = stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 1));
} }
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = ThreeGangModel.fromJson(statusList); deviceStatus = ThreeGangModel.fromJson(statusList);
if (!isClosed) { if (!isClosed) {
add(ThreeGangUpdated()); add(ThreeGangUpdated());
@ -133,11 +143,19 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} catch (_) {} } catch (_) {}
} }
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_threeGangUpdated(ThreeGangUpdated event, Emitter<ThreeGangState> emit) { _threeGangUpdated(ThreeGangUpdated event, Emitter<ThreeGangState> emit) {
emit(UpdateState(threeGangModel: deviceStatus)); emit(UpdateState(threeGangModel: deviceStatus));
} }
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<ThreeGangState> emit) async { void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<ThreeGangState> emit) async {
emit(LoadingNewSate(threeGangModel: deviceStatus)); emit(LoadingNewSate(threeGangModel: deviceStatus));
try { try {
if (threeGangGroup) { if (threeGangGroup) {
@ -146,11 +164,14 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
if (element.deviceId == event.deviceId) { if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value; element.firstSwitch = !event.value;
} }
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
} else { } else {
deviceStatus.firstSwitch = !event.value; deviceStatus.firstSwitch = !event.value;
emit(UpdateState(threeGangModel: deviceStatus)); emit(UpdateState(threeGangModel: deviceStatus));
@ -187,11 +208,14 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
if (element.deviceId == event.deviceId) { if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value; element.secondSwitch = !event.value;
} }
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
} else { } else {
deviceStatus.secondSwitch = !event.value; deviceStatus.secondSwitch = !event.value;
emit(UpdateState(threeGangModel: deviceStatus)); emit(UpdateState(threeGangModel: deviceStatus));
@ -217,7 +241,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
} }
void _changeThirdSwitch(ChangeThirdSwitchStatusEvent event, Emitter<ThreeGangState> emit) async { void _changeThirdSwitch(
ChangeThirdSwitchStatusEvent event, Emitter<ThreeGangState> emit) async {
emit(LoadingNewSate(threeGangModel: deviceStatus)); emit(LoadingNewSate(threeGangModel: deviceStatus));
try { try {
if (threeGangGroup) { if (threeGangGroup) {
@ -226,11 +251,14 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
if (element.deviceId == event.deviceId) { if (element.deviceId == event.deviceId) {
element.thirdSwitch = !event.value; element.thirdSwitch = !event.value;
} }
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
threeGangList: groupThreeGangList, allSwitches: allSwitchesValue));
} else { } else {
deviceStatus.thirdSwitch = !event.value; deviceStatus.thirdSwitch = !event.value;
emit(UpdateState(threeGangModel: deviceStatus)); emit(UpdateState(threeGangModel: deviceStatus));
@ -269,15 +297,21 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeGangId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: threeGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
threeGangId), threeGangId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeGangId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: threeGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
threeGangId), threeGangId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeGangId, code: 'switch_3', value: deviceStatus.thirdSwitch), deviceId: threeGangId,
code: 'switch_3',
value: deviceStatus.thirdSwitch),
threeGangId), threeGangId),
]); ]);
@ -303,15 +337,21 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeGangId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: threeGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
threeGangId), threeGangId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeGangId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: threeGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
threeGangId), threeGangId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeGangId, code: 'switch_3', value: deviceStatus.thirdSwitch), deviceId: threeGangId,
code: 'switch_3',
value: deviceStatus.thirdSwitch),
threeGangId), threeGangId),
]); ]);
@ -333,9 +373,11 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
groupThreeGangList[i].secondSwitch = true; groupThreeGangList[i].secondSwitch = true;
groupThreeGangList[i].thirdSwitch = true; groupThreeGangList[i].thirdSwitch = true;
} }
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: true)); emit(UpdateGroupState(
threeGangList: groupThreeGangList, allSwitches: true));
List<String> allDeviceIds = groupThreeGangList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupThreeGangList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -365,7 +407,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
} }
void _groupAllOff(GroupAllOffEvent event, Emitter<ThreeGangState> emit) async { void _groupAllOff(
GroupAllOffEvent event, Emitter<ThreeGangState> emit) async {
emit(LoadingNewSate(threeGangModel: deviceStatus)); emit(LoadingNewSate(threeGangModel: deviceStatus));
try { try {
for (int i = 0; i < groupThreeGangList.length; i++) { for (int i = 0; i < groupThreeGangList.length; i++) {
@ -373,8 +416,10 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
groupThreeGangList[i].secondSwitch = false; groupThreeGangList[i].secondSwitch = false;
groupThreeGangList[i].thirdSwitch = false; groupThreeGangList[i].thirdSwitch = false;
} }
emit(UpdateGroupState(threeGangList: groupThreeGangList, allSwitches: false)); emit(UpdateGroupState(
List<String> allDeviceIds = groupThreeGangList.map((device) => device.deviceId).toList(); threeGangList: groupThreeGangList, allSwitches: false));
List<String> allDeviceIds =
groupThreeGangList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -404,17 +449,20 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
} }
void _changeSliding(ChangeSlidingSegment event, Emitter<ThreeGangState> emit) async { void _changeSliding(
ChangeSlidingSegment event, Emitter<ThreeGangState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value)); emit(ChangeSlidingSegmentState(value: event.value));
} }
void _setCounterValue(SetCounterValue event, Emitter<ThreeGangState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<ThreeGangState> emit) async {
emit(LoadingNewSate(threeGangModel: deviceStatus)); emit(LoadingNewSate(threeGangModel: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: threeGangId, code: event.deviceCode, value: seconds), DeviceControlModel(
deviceId: threeGangId, code: event.deviceCode, value: seconds),
threeGangId); threeGangId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
@ -441,7 +489,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<ThreeGangState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<ThreeGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(threeGangId); var response = await DevicesAPI.getDeviceStatus(threeGangId);
@ -551,7 +600,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
deviceId: threeGangId, deviceId: threeGangId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState()); emit(InitialState());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -562,12 +612,13 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleChange(ToggleScheduleEvent event, Emitter<ThreeGangState> emit) async { Future toggleChange(
ToggleScheduleEvent event, Emitter<ThreeGangState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -586,7 +637,8 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<ThreeGangState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<ThreeGangState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -606,13 +658,15 @@ class ThreeGangBloc extends Bloc<ThreeGangEvent, ThreeGangState> {
} }
} }
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<ThreeGangState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<ThreeGangState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<ThreeGangState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<ThreeGangState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();

View File

@ -38,7 +38,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
List<GroupThreeTouchModel> groupThreeTouchList = []; List<GroupThreeTouchModel> groupThreeTouchList = [];
bool allSwitchesOn = true; bool allSwitchesOn = true;
ThreeTouchBloc({required this.threeTouchId, required this.switchCode}) : super(InitialState()) { ThreeTouchBloc({required this.threeTouchId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchThreeTouchStatus); on<InitialEvent>(_fetchThreeTouchStatus);
on<ThreeTouchUpdated>(_threeTouchUpdated); on<ThreeTouchUpdated>(_threeTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch); on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -63,7 +64,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
on<ChangeStatusEvent>(_changeStatus); on<ChangeStatusEvent>(_changeStatus);
} }
void _fetchThreeTouchStatus(InitialEvent event, Emitter<ThreeTouchState> emit) async { void _fetchThreeTouchStatus(
InitialEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
threeTouchGroup = event.groupScreen; threeTouchGroup = event.groupScreen;
@ -75,7 +77,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '3GT'); HomeCubit.getInstance().selectedSpace?.id ?? '', '3GT');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -92,13 +95,16 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
if (groupThreeTouchList.isNotEmpty) { if (groupThreeTouchList.isNotEmpty) {
groupThreeTouchList.firstWhere((element) { groupThreeTouchList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesOn = false; allSwitchesOn = false;
} }
return true; return true;
}); });
} }
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesOn)); emit(UpdateGroupState(
threeTouchList: groupThreeTouchList, allSwitches: allSwitchesOn));
} else { } else {
var response = await DevicesAPI.getDeviceStatus(threeTouchId); var response = await DevicesAPI.getDeviceStatus(threeTouchId);
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
@ -107,7 +113,7 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
deviceStatus = ThreeTouchModel.fromJson(statusModelList); deviceStatus = ThreeTouchModel.fromJson(statusModelList);
emit(UpdateState(threeTouchModel: deviceStatus)); emit(UpdateState(threeTouchModel: deviceStatus));
// _listenToChanges(); _listenToChanges();
} }
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
@ -117,18 +123,21 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
_listenToChanges() { _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$threeTouchId'); DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$threeTouchId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
} }
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = ThreeTouchModel.fromJson(statusList); deviceStatus = ThreeTouchModel.fromJson(statusList);
@ -143,7 +152,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
emit(UpdateState(threeTouchModel: deviceStatus)); emit(UpdateState(threeTouchModel: deviceStatus));
} }
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async { void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus)); emit(LoadingNewSate(threeTouchModel: deviceStatus));
try { try {
if (threeTouchGroup) { if (threeTouchGroup) {
@ -152,11 +162,15 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
if (element.deviceId == event.deviceId) { if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value; element.firstSwitch = !event.value;
} }
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
threeTouchList: groupThreeTouchList,
allSwitches: allSwitchesValue));
} else { } else {
deviceStatus.firstSwitch = !event.value; deviceStatus.firstSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus)); emit(UpdateState(threeTouchModel: deviceStatus));
@ -183,8 +197,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
} }
void _changeSecondSwitch( void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event,
ChangeSecondSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async { Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus)); emit(LoadingNewSate(threeTouchModel: deviceStatus));
try { try {
if (threeTouchGroup) { if (threeTouchGroup) {
@ -193,11 +207,15 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
if (element.deviceId == event.deviceId) { if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value; element.secondSwitch = !event.value;
} }
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
threeTouchList: groupThreeTouchList,
allSwitches: allSwitchesValue));
} else { } else {
deviceStatus.secondSwitch = !event.value; deviceStatus.secondSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus)); emit(UpdateState(threeTouchModel: deviceStatus));
@ -223,7 +241,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
} }
void _changeThirdSwitch(ChangeThirdSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async { void _changeThirdSwitch(
ChangeThirdSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus)); emit(LoadingNewSate(threeTouchModel: deviceStatus));
try { try {
if (threeTouchGroup) { if (threeTouchGroup) {
@ -232,11 +251,15 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
if (element.deviceId == event.deviceId) { if (element.deviceId == event.deviceId) {
element.thirdSwitch = !event.value; element.thirdSwitch = !event.value;
} }
if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
threeTouchList: groupThreeTouchList,
allSwitches: allSwitchesValue));
} else { } else {
deviceStatus.thirdSwitch = !event.value; deviceStatus.thirdSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus)); emit(UpdateState(threeTouchModel: deviceStatus));
@ -275,15 +298,21 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeTouchId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: threeTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
threeTouchId), threeTouchId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeTouchId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: threeTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
threeTouchId), threeTouchId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeTouchId, code: 'switch_3', value: deviceStatus.thirdSwitch), deviceId: threeTouchId,
code: 'switch_3',
value: deviceStatus.thirdSwitch),
threeTouchId), threeTouchId),
]); ]);
@ -309,15 +338,21 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeTouchId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: threeTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
threeTouchId), threeTouchId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeTouchId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: threeTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
threeTouchId), threeTouchId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: threeTouchId, code: 'switch_3', value: deviceStatus.thirdSwitch), deviceId: threeTouchId,
code: 'switch_3',
value: deviceStatus.thirdSwitch),
threeTouchId), threeTouchId),
]); ]);
@ -339,8 +374,10 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
groupThreeTouchList[i].secondSwitch = true; groupThreeTouchList[i].secondSwitch = true;
groupThreeTouchList[i].thirdSwitch = true; groupThreeTouchList[i].thirdSwitch = true;
} }
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: true)); emit(UpdateGroupState(
List<String> allDeviceIds = groupThreeTouchList.map((device) => device.deviceId).toList(); threeTouchList: groupThreeTouchList, allSwitches: true));
List<String> allDeviceIds =
groupThreeTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
devicesUuid: allDeviceIds, devicesUuid: allDeviceIds,
@ -369,7 +406,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
} }
void _groupAllOff(GroupAllOffEvent event, Emitter<ThreeTouchState> emit) async { void _groupAllOff(
GroupAllOffEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus)); emit(LoadingNewSate(threeTouchModel: deviceStatus));
try { try {
for (int i = 0; i < groupThreeTouchList.length; i++) { for (int i = 0; i < groupThreeTouchList.length; i++) {
@ -377,8 +415,10 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
groupThreeTouchList[i].secondSwitch = false; groupThreeTouchList[i].secondSwitch = false;
groupThreeTouchList[i].thirdSwitch = false; groupThreeTouchList[i].thirdSwitch = false;
} }
List<String> allDeviceIds = groupThreeTouchList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: false)); groupThreeTouchList.map((device) => device.deviceId).toList();
emit(UpdateGroupState(
threeTouchList: groupThreeTouchList, allSwitches: false));
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
devicesUuid: allDeviceIds, devicesUuid: allDeviceIds,
@ -407,17 +447,20 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
} }
void _changeSliding(ChangeSlidingSegment event, Emitter<ThreeTouchState> emit) async { void _changeSliding(
ChangeSlidingSegment event, Emitter<ThreeTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value)); emit(ChangeSlidingSegmentState(value: event.value));
} }
void _setCounterValue(SetCounterValue event, Emitter<ThreeTouchState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus)); emit(LoadingNewSate(threeTouchModel: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: threeTouchId, code: event.deviceCode, value: seconds), DeviceControlModel(
deviceId: threeTouchId, code: event.deviceCode, value: seconds),
threeTouchId); threeTouchId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
@ -444,7 +487,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<ThreeTouchState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(threeTouchId); var response = await DevicesAPI.getDeviceStatus(threeTouchId);
@ -554,7 +598,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
deviceId: threeTouchId, deviceId: threeTouchId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState()); emit(InitialState());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -565,12 +610,13 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleChange(ToggleScheduleEvent event, Emitter<ThreeTouchState> emit) async { Future toggleChange(
ToggleScheduleEvent event, Emitter<ThreeTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -589,7 +635,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<ThreeTouchState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<ThreeTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -609,13 +656,15 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
} }
} }
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<ThreeTouchState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<ThreeTouchState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<ThreeTouchState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<ThreeTouchState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();
@ -633,7 +682,8 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
String statusSelected = ''; String statusSelected = '';
String optionSelected = ''; String optionSelected = '';
Future<void> _changeStatus(ChangeStatusEvent event, Emitter<ThreeTouchState> emit) async { Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<ThreeTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final Map<String, Map<String, String>> controlMap = { final Map<String, Map<String, String>> controlMap = {
@ -667,11 +717,15 @@ class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
final selectedControl = controlMap[optionSelected]?[statusSelected]; final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) { if (selectedControl != null) {
await DevicesAPI.controlDevice( await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: threeTouchId, code: optionSelected, value: selectedControl), DeviceControlModel(
deviceId: threeTouchId,
code: optionSelected,
value: selectedControl),
threeTouchId, threeTouchId,
); );
} else { } else {
emit(const FailedState(error: 'Invalid statusSelected or optionSelected')); emit(const FailedState(
error: 'Invalid statusSelected or optionSelected'));
} }
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;

View File

@ -35,7 +35,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
bool createSchedule = false; bool createSchedule = false;
List<ScheduleModel> listSchedule = []; List<ScheduleModel> listSchedule = [];
TwoGangBloc({required this.twoGangId, required this.switchCode}) : super(InitialState()) { TwoGangBloc({required this.twoGangId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchTwoGangStatus); on<InitialEvent>(_fetchTwoGangStatus);
on<TwoGangUpdated>(_twoGangUpdated); on<TwoGangUpdated>(_twoGangUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch); on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -65,13 +66,15 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
int selectedTabIndex = 0; int selectedTabIndex = 0;
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<TwoGangState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<TwoGangState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<TwoGangState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<TwoGangState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();
@ -79,7 +82,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
emit(UpdateCreateScheduleState(createSchedule)); emit(UpdateCreateScheduleState(createSchedule));
} }
void _fetchTwoGangStatus(InitialEvent event, Emitter<TwoGangState> emit) async { void _fetchTwoGangStatus(
InitialEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(twoGangId); var response = await DevicesAPI.getDeviceStatus(twoGangId);
@ -89,42 +93,50 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
deviceStatus = TwoGangModel.fromJson(statusModelList); deviceStatus = TwoGangModel.fromJson(statusModelList);
emit(UpdateState(twoGangModel: deviceStatus)); emit(UpdateState(twoGangModel: deviceStatus));
// _listenToChanges(); _listenToChanges(twoGangId);
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
_listenToChanges() { StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges(String id) {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoGangId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$id');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
_streamSubscription = stream.listen((DatabaseEvent event) {
stream.listen((DatabaseEvent event) async { Map<dynamic, dynamic> usersMap =
if (_timer != null) { event.snapshot.value as Map<dynamic, dynamic>;
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = TwoGangModel.fromJson(statusList); deviceStatus = TwoGangModel.fromJson(statusList);
if (!isClosed) { add(TwoGangUpdated());
add(TwoGangUpdated());
}
}); });
} catch (_) {} } catch (_) {}
} }
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_twoGangUpdated(TwoGangUpdated event, Emitter<TwoGangState> emit) { _twoGangUpdated(TwoGangUpdated event, Emitter<TwoGangState> emit) {
emit(LoadingNewSate(twoGangModel: deviceStatus));
emit(UpdateState(twoGangModel: deviceStatus)); emit(UpdateState(twoGangModel: deviceStatus));
} }
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<TwoGangState> emit) async { void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus)); emit(LoadingNewSate(twoGangModel: deviceStatus));
try { try {
deviceStatus.firstSwitch = !event.value; deviceStatus.firstSwitch = !event.value;
@ -135,7 +147,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
_timer = Timer(const Duration(milliseconds: 100), () async { _timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoGangId, code: 'switch_1', value: !event.value), DeviceControlModel(
deviceId: twoGangId, code: 'switch_1', value: !event.value),
twoGangId); twoGangId);
if (!response['success']) { if (!response['success']) {
@ -147,7 +160,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
} }
void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter<TwoGangState> emit) async { void _changeSecondSwitch(
ChangeSecondSwitchStatusEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus)); emit(LoadingNewSate(twoGangModel: deviceStatus));
try { try {
deviceStatus.secondSwitch = !event.value; deviceStatus.secondSwitch = !event.value;
@ -157,7 +171,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
_timer = Timer(const Duration(milliseconds: 100), () async { _timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoGangId, code: 'switch_2', value: !event.value), DeviceControlModel(
deviceId: twoGangId, code: 'switch_2', value: !event.value),
twoGangId); twoGangId);
if (!response['success']) { if (!response['success']) {
@ -180,11 +195,15 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: twoGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoGangId), twoGangId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: twoGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoGangId), twoGangId),
]); ]);
@ -207,11 +226,15 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: twoGangId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoGangId), twoGangId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: twoGangId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoGangId), twoGangId),
]); ]);
if (response.every((element) => !element['success'])) { if (response.every((element) => !element['success'])) {
@ -232,7 +255,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
groupTwoGangList[i].secondSwitch = true; groupTwoGangList[i].secondSwitch = true;
} }
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: true)); emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: true));
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -267,7 +291,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: false)); emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: false));
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -292,17 +317,20 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
} }
void _changeSliding(ChangeSlidingSegment event, Emitter<TwoGangState> emit) async { void _changeSliding(
ChangeSlidingSegment event, Emitter<TwoGangState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value)); emit(ChangeSlidingSegmentState(value: event.value));
} }
void _setCounterValue(SetCounterValue event, Emitter<TwoGangState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus)); emit(LoadingNewSate(twoGangModel: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoGangId, code: event.deviceCode, value: seconds), DeviceControlModel(
deviceId: twoGangId, code: event.deviceCode, value: seconds),
twoGangId); twoGangId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
@ -327,7 +355,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<TwoGangState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
add(GetScheduleEvent()); add(GetScheduleEvent());
@ -435,7 +464,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
deviceId: twoGangId, deviceId: twoGangId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState()); emit(InitialState());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -446,12 +476,13 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleRepeat(ToggleScheduleEvent event, Emitter<TwoGangState> emit) async { Future toggleRepeat(
ToggleScheduleEvent event, Emitter<TwoGangState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -470,7 +501,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<TwoGangState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<TwoGangState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -490,7 +522,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
} }
void _fetchTwoGangWizardStatus(InitialWizardEvent event, Emitter<TwoGangState> emit) async { void _fetchTwoGangWizardStatus(
InitialWizardEvent event, Emitter<TwoGangState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
devicesList = []; devicesList = [];
@ -500,7 +533,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '2G'); HomeCubit.getInstance().selectedSpace?.id ?? '', '2G');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -523,15 +557,16 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
return true; return true;
}); });
} }
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); emit(UpdateGroupState(
twoGangList: groupTwoGangList, allSwitches: allSwitchesOn));
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
void _changeFirstWizardSwitch( void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
ChangeFirstWizardSwitchStatusEvent event, Emitter<TwoGangState> emit) async { Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus)); emit(LoadingNewSate(twoGangModel: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -544,9 +579,11 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
}); });
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
twoGangList: groupTwoGangList, allSwitches: allSwitchesValue));
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
devicesUuid: allDeviceIds, devicesUuid: allDeviceIds,
@ -561,8 +598,8 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
} }
} }
void _changeSecondWizardSwitch( void _changeSecondWizardSwitch(ChangeSecondWizardSwitchStatusEvent event,
ChangeSecondWizardSwitchStatusEvent event, Emitter<TwoGangState> emit) async { Emitter<TwoGangState> emit) async {
emit(LoadingNewSate(twoGangModel: deviceStatus)); emit(LoadingNewSate(twoGangModel: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -574,9 +611,11 @@ class TwoGangBloc extends Bloc<TwoGangEvent, TwoGangState> {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
List<String> allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupTwoGangList.map((device) => device.deviceId).toList();
emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
twoGangList: groupTwoGangList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_2', code: 'switch_2',

View File

@ -40,7 +40,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
bool createSchedule = false; bool createSchedule = false;
List<ScheduleModel> listSchedule = []; List<ScheduleModel> listSchedule = [];
TwoTouchBloc({required this.twoTouchId, required this.switchCode}) : super(InitialState()) { TwoTouchBloc({required this.twoTouchId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchTwoTouchStatus); on<InitialEvent>(_fetchTwoTouchStatus);
on<TwoTouchUpdated>(_twoTouchUpdated); on<TwoTouchUpdated>(_twoTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch); on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
@ -71,13 +72,15 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
int selectedTabIndex = 0; int selectedTabIndex = 0;
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<TwoTouchState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<TwoTouchState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<TwoTouchState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<TwoTouchState> emit) {
emit(LoadingInitialState()); emit(LoadingInitialState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();
@ -85,7 +88,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
emit(UpdateCreateScheduleState(createSchedule)); emit(UpdateCreateScheduleState(createSchedule));
} }
void _fetchTwoTouchStatus(InitialEvent event, Emitter<TwoTouchState> emit) async { void _fetchTwoTouchStatus(
InitialEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(twoTouchId); var response = await DevicesAPI.getDeviceStatus(twoTouchId);
@ -95,42 +99,66 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
deviceStatus = TwoTouchModel.fromJson(statusModelList); deviceStatus = TwoTouchModel.fromJson(statusModelList);
emit(UpdateState(twoTouchModel: deviceStatus)); emit(UpdateState(twoTouchModel: deviceStatus));
// _listenToChanges(); _listenToChanges();
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
_listenToChanges() { StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoTouchId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$twoTouchId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { _streamSubscription = stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 1));
} }
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; if (event.snapshot.value != null) {
List<StatusModel> statusList = []; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList.add(
}); StatusModel(code: element['code'], value: element['value']));
});
var switch1Status = statusList.firstWhere(
(status) => status.code == "switch_1",
orElse: () => StatusModel(code: "switch_1", value: false));
var switch2Status = statusList.firstWhere(
(status) => status.code == "switch_2",
orElse: () => StatusModel(code: "switch_2", value: false));
deviceStatus.firstSwitch = switch1Status.value as bool;
deviceStatus.secondSwitch = switch2Status.value as bool;
deviceStatus = TwoTouchModel.fromJson(statusList);
if (!isClosed) {
add(TwoTouchUpdated()); add(TwoTouchUpdated());
} }
}); });
} catch (_) {} } catch (_) {
}
}
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
} }
_twoTouchUpdated(TwoTouchUpdated event, Emitter<TwoTouchState> emit) { _twoTouchUpdated(TwoTouchUpdated event, Emitter<TwoTouchState> emit) {
emit(LoadingInitialState());
emit(UpdateState(twoTouchModel: deviceStatus)); emit(UpdateState(twoTouchModel: deviceStatus));
} }
void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter<TwoTouchState> emit) async { void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus)); emit(LoadingNewSate(twoTouchModel: deviceStatus));
try { try {
deviceStatus.firstSwitch = !event.value; deviceStatus.firstSwitch = !event.value;
@ -141,7 +169,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
_timer = Timer(const Duration(milliseconds: 100), () async { _timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: 'switch_1', value: !event.value), DeviceControlModel(
deviceId: twoTouchId, code: 'switch_1', value: !event.value),
twoTouchId); twoTouchId);
if (!response['success']) { if (!response['success']) {
@ -153,7 +182,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
} }
void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter<TwoTouchState> emit) async { void _changeSecondSwitch(
ChangeSecondSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus)); emit(LoadingNewSate(twoTouchModel: deviceStatus));
try { try {
deviceStatus.secondSwitch = !event.value; deviceStatus.secondSwitch = !event.value;
@ -163,7 +193,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
_timer = Timer(const Duration(milliseconds: 100), () async { _timer = Timer(const Duration(milliseconds: 100), () async {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: 'switch_2', value: !event.value), DeviceControlModel(
deviceId: twoTouchId, code: 'switch_2', value: !event.value),
twoTouchId); twoTouchId);
if (!response['success']) { if (!response['success']) {
@ -186,11 +217,15 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoTouchId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: twoTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoTouchId), twoTouchId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoTouchId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: twoTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoTouchId), twoTouchId),
]); ]);
@ -213,11 +248,15 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
final response = await Future.wait([ final response = await Future.wait([
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoTouchId, code: 'switch_1', value: deviceStatus.firstSwitch), deviceId: twoTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoTouchId), twoTouchId),
DevicesAPI.controlDevice( DevicesAPI.controlDevice(
DeviceControlModel( DeviceControlModel(
deviceId: twoTouchId, code: 'switch_2', value: deviceStatus.secondSwitch), deviceId: twoTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoTouchId), twoTouchId),
]); ]);
if (response.every((element) => !element['success'])) { if (response.every((element) => !element['success'])) {
@ -237,8 +276,10 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
groupTwoTouchList[i].firstSwitch = true; groupTwoTouchList[i].firstSwitch = true;
groupTwoTouchList[i].secondSwitch = true; groupTwoTouchList[i].secondSwitch = true;
} }
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: true)); emit(
List<String> allDeviceIds = groupTwoTouchList.map((device) => device.deviceId).toList(); UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: true));
List<String> allDeviceIds =
groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -271,9 +312,11 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
groupTwoTouchList[i].secondSwitch = false; groupTwoTouchList[i].secondSwitch = false;
} }
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: false)); emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: false));
List<String> allDeviceIds = groupTwoTouchList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController( final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -298,17 +341,20 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
} }
void _changeSliding(ChangeSlidingSegment event, Emitter<TwoTouchState> emit) async { void _changeSliding(
ChangeSlidingSegment event, Emitter<TwoTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value)); emit(ChangeSlidingSegmentState(value: event.value));
} }
void _setCounterValue(SetCounterValue event, Emitter<TwoTouchState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus)); emit(LoadingNewSate(twoTouchModel: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: event.deviceCode, value: seconds), DeviceControlModel(
deviceId: twoTouchId, code: event.deviceCode, value: seconds),
twoTouchId); twoTouchId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
@ -333,7 +379,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<TwoTouchState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
add(GetScheduleEvent()); add(GetScheduleEvent());
@ -441,7 +488,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
deviceId: twoTouchId, deviceId: twoTouchId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState()); emit(InitialState());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -452,12 +500,13 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleRepeat(ToggleScheduleEvent event, Emitter<TwoTouchState> emit) async { Future toggleRepeat(
ToggleScheduleEvent event, Emitter<TwoTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -476,7 +525,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<TwoTouchState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<TwoTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -496,7 +546,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
} }
void _fetchTwoTouchWizardStatus(InitialWizardEvent event, Emitter<TwoTouchState> emit) async { void _fetchTwoTouchWizardStatus(
InitialWizardEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
devicesList = []; devicesList = [];
@ -506,7 +557,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', '2GT'); HomeCubit.getInstance().selectedSpace?.id ?? '', '2GT');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -529,15 +581,16 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
return true; return true;
}); });
} }
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesOn)); emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: allSwitchesOn));
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
void _changeFirstWizardSwitch( void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
ChangeFirstWizardSwitchStatusEvent event, Emitter<TwoTouchState> emit) async { Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus)); emit(LoadingNewSate(twoTouchModel: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -550,7 +603,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
}); });
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
devicesUuid: [event.deviceId], devicesUuid: [event.deviceId],
@ -565,8 +619,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
} }
void _changeSecondWizardSwitch( void _changeSecondWizardSwitch(ChangeSecondWizardSwitchStatusEvent event,
ChangeSecondWizardSwitchStatusEvent event, Emitter<TwoTouchState> emit) async { Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus)); emit(LoadingNewSate(twoTouchModel: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -579,7 +633,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
} }
}); });
emit(UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_2', code: 'switch_2',
@ -598,7 +653,8 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
String statusSelected = ''; String statusSelected = '';
String optionSelected = ''; String optionSelected = '';
Future<void> _changeStatus(ChangeStatusEvent event, Emitter<TwoTouchState> emit) async { Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<TwoTouchState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
final Map<String, Map<String, String>> controlMap = { final Map<String, Map<String, String>> controlMap = {
@ -627,11 +683,15 @@ class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
final selectedControl = controlMap[optionSelected]?[statusSelected]; final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) { if (selectedControl != null) {
await DevicesAPI.controlDevice( await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: twoTouchId, code: optionSelected, value: selectedControl), DeviceControlModel(
deviceId: twoTouchId,
code: optionSelected,
value: selectedControl),
twoTouchId, twoTouchId,
); );
} else { } else {
emit(const FailedState(error: 'Invalid statusSelected or optionSelected')); emit(const FailedState(
error: 'Invalid statusSelected or optionSelected'));
} }
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.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_state.dart';
@ -18,9 +20,11 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
on<ChangeIndicatorEvent>(_changeIndicator); on<ChangeIndicatorEvent>(_changeIndicator);
on<ChangeValueEvent>(_changeValue); on<ChangeValueEvent>(_changeValue);
on<WallSensorUpdatedEvent>(_wallSensorUpdated); on<WallSensorUpdatedEvent>(_wallSensorUpdated);
on<GetDeviceReportsEvent>(_getDeviceReports);
} }
void _fetchCeilingSensorStatus(InitialEvent event, Emitter<WallSensorState> emit) async { void _fetchCeilingSensorStatus(
InitialEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
var response = await DevicesAPI.getDeviceStatus(deviceId); var response = await DevicesAPI.getDeviceStatus(deviceId);
@ -30,41 +34,62 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
} }
deviceStatus = WallSensorModel.fromJson(statusModelList); deviceStatus = WallSensorModel.fromJson(statusModelList);
emit(UpdateState(wallSensorModel: deviceStatus)); emit(UpdateState(wallSensorModel: deviceStatus));
// _listenToChanges(); _listenToChanges();
} catch (e) { } catch (e) {
emit(FailedState(error: e.toString())); emit(FailedState(error: e.toString()));
return; return;
} }
} }
_listenToChanges() { Timer? _timer;
StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$deviceId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) { _streamSubscription = stream.listen((DatabaseEvent event) async {
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; if (_timer != null) {
await Future.delayed(const Duration(seconds: 2));
}
Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = WallSensorModel.fromJson(statusList); deviceStatus = WallSensorModel.fromJson(statusList);
add(WallSensorUpdatedEvent()); if (!isClosed) {
add(WallSensorUpdatedEvent());
}
}); });
} catch (_) {} } catch (_) {}
} }
_wallSensorUpdated(WallSensorUpdatedEvent event, Emitter<WallSensorState> emit) { @override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_wallSensorUpdated(
WallSensorUpdatedEvent event, Emitter<WallSensorState> emit) {
emit(UpdateState(wallSensorModel: deviceStatus)); emit(UpdateState(wallSensorModel: deviceStatus));
} }
void _changeIndicator(ChangeIndicatorEvent event, Emitter<WallSensorState> emit) async { void _changeIndicator(
ChangeIndicatorEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingNewSate(wallSensorModel: deviceStatus)); emit(LoadingNewSate(wallSensorModel: deviceStatus));
try { try {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: deviceId, code: 'indicator', value: !event.value), deviceId); DeviceControlModel(
deviceId: deviceId, code: 'indicator', value: !event.value),
deviceId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
deviceStatus.indicator = !event.value; deviceStatus.indicator = !event.value;
@ -73,11 +98,14 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
emit(UpdateState(wallSensorModel: deviceStatus)); emit(UpdateState(wallSensorModel: deviceStatus));
} }
void _changeValue(ChangeValueEvent event, Emitter<WallSensorState> emit) async { void _changeValue(
ChangeValueEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingNewSate(wallSensorModel: deviceStatus)); emit(LoadingNewSate(wallSensorModel: deviceStatus));
try { try {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: deviceId, code: event.code, value: event.value), deviceId); DeviceControlModel(
deviceId: deviceId, code: event.code, value: event.value),
deviceId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
if (event.code == 'far_detection') { if (event.code == 'far_detection') {
@ -91,4 +119,18 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
} catch (_) {} } catch (_) {}
emit(UpdateState(wallSensorModel: deviceStatus)); emit(UpdateState(wallSensorModel: deviceStatus));
} }
void _getDeviceReports(
GetDeviceReportsEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingInitialState());
try {
await DevicesAPI.getDeviceReports(deviceId, event.code).then((value) {
emit(DeviceReportsState(deviceReport: value, code: event.code));
});
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
} }

View File

@ -29,3 +29,15 @@ class ChangeValueEvent extends WallSensorEvent {
@override @override
List<Object> get props => [value, code]; List<Object> get props => [value, code];
} }
class GetDeviceReportsEvent extends WallSensorEvent {
final String deviceUuid;
final String code;
const GetDeviceReportsEvent({
required this.deviceUuid,
required this.code,
});
@override
List<Object> get props => [deviceUuid, code];
}

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart'; import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart';
class WallSensorState extends Equatable { class WallSensorState extends Equatable {
@ -36,3 +37,9 @@ class FailedState extends WallSensorState {
@override @override
List<Object> get props => [error]; List<Object> get props => [error];
} }
class DeviceReportsState extends WallSensorState {
final DeviceReport deviceReport;
final String code;
const DeviceReportsState({required this.deviceReport, required this.code});
}

View File

@ -35,7 +35,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
List<ScheduleModel> listSchedule = []; List<ScheduleModel> listSchedule = [];
DateTime? selectedTime = DateTime.now(); DateTime? selectedTime = DateTime.now();
WaterHeaterBloc({required this.whId, required this.switchCode}) : super(WHInitialState()) { WaterHeaterBloc({required this.whId, required this.switchCode})
: super(WHInitialState()) {
on<WaterHeaterInitial>(_fetchWaterHeaterStatus); on<WaterHeaterInitial>(_fetchWaterHeaterStatus);
on<WaterHeaterSwitch>(_changeFirstSwitch); on<WaterHeaterSwitch>(_changeFirstSwitch);
on<SetCounterValue>(_setCounterValue); on<SetCounterValue>(_setCounterValue);
@ -60,7 +61,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
on<WaterHeaterUpdated>(_waterHeaterUpdated); on<WaterHeaterUpdated>(_waterHeaterUpdated);
} }
void _fetchWaterHeaterStatus(WaterHeaterInitial event, Emitter<WaterHeaterState> emit) async { void _fetchWaterHeaterStatus(
WaterHeaterInitial event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState()); emit(WHLoadingState());
try { try {
var response = await DevicesAPI.getDeviceStatus(whId); var response = await DevicesAPI.getDeviceStatus(whId);
@ -72,29 +74,33 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
statusModelList, statusModelList,
); );
emit(UpdateState(whModel: deviceStatus)); emit(UpdateState(whModel: deviceStatus));
// _listenToChanges(); _listenToChanges();
} catch (e) { } catch (e) {
emit(WHFailedState(errorMessage: e.toString())); emit(WHFailedState(errorMessage: e.toString()));
return; return;
} }
} }
_listenToChanges() { //real-time db
StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges() {
try { try {
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$whId'); _streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$whId');
Stream<DatabaseEvent> stream = ref.onValue; Stream<DatabaseEvent> stream = ref.onValue;
stream.listen((DatabaseEvent event) async { _streamSubscription = stream.listen((DatabaseEvent event) async {
if (_timer != null) { if (_timer != null) {
await Future.delayed(const Duration(seconds: 2)); await Future.delayed(const Duration(seconds: 2));
} }
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>; Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = []; List<StatusModel> statusList = [];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value'])); statusList
.add(StatusModel(code: element['code'], value: element['value']));
}); });
deviceStatus = WHModel.fromJson(statusList); deviceStatus = WHModel.fromJson(statusList);
if (!isClosed) { if (!isClosed) {
add(WaterHeaterUpdated()); add(WaterHeaterUpdated());
@ -103,12 +109,21 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} catch (_) {} } catch (_) {}
} }
_waterHeaterUpdated(WaterHeaterUpdated event, Emitter<WaterHeaterState> emit) async { @override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_waterHeaterUpdated(
WaterHeaterUpdated event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState()); emit(WHLoadingState());
emit(UpdateState(whModel: deviceStatus)); emit(UpdateState(whModel: deviceStatus));
} }
void _changeFirstSwitch(WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async { void _changeFirstSwitch(
WaterHeaterSwitch event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus)); emit(LoadingNewSate(whModel: deviceStatus));
try { try {
deviceStatus.firstSwitch = !event.whSwitch; deviceStatus.firstSwitch = !event.whSwitch;
@ -118,7 +133,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
_timer = Timer(const Duration(milliseconds: 500), () async { _timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: whId, code: 'switch_1', value: deviceStatus.firstSwitch), DeviceControlModel(
deviceId: whId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
whId); whId);
if (!response['success']) { if (!response['success']) {
@ -132,13 +150,16 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
//=====================---------- timer ---------------------------------------- //=====================---------- timer ----------------------------------------
void _setCounterValue(SetCounterValue event, Emitter<WaterHeaterState> emit) async { void _setCounterValue(
SetCounterValue event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus)); emit(LoadingNewSate(whModel: deviceStatus));
int seconds = 0; int seconds = 0;
try { try {
seconds = event.duration.inSeconds; seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice( final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: whId, code: event.deviceCode, value: seconds), whId); DeviceControlModel(
deviceId: whId, code: event.deviceCode, value: seconds),
whId);
if (response['success'] ?? false) { if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') { if (event.deviceCode == 'countdown_1') {
@ -160,7 +181,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
void _getCounterValue(GetCounterEvent event, Emitter<WaterHeaterState> emit) async { void _getCounterValue(
GetCounterEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState()); emit(WHLoadingState());
try { try {
var response = await DevicesAPI.getDeviceStatus(whId); var response = await DevicesAPI.getDeviceStatus(whId);
@ -250,7 +272,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
deviceId: whId, deviceId: whId,
); );
List<dynamic> jsonData = response; List<dynamic> jsonData = response;
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(WHInitialState()); emit(WHInitialState());
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -261,12 +284,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
int? getTimeStampWithoutSeconds(DateTime? dateTime) { int? getTimeStampWithoutSeconds(DateTime? dateTime) {
if (dateTime == null) return null; if (dateTime == null) return null;
DateTime dateTimeWithoutSeconds = DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); dateTime.day, dateTime.hour, dateTime.minute);
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
} }
Future toggleChange(ToggleScheduleEvent event, Emitter<WaterHeaterState> emit) async { Future toggleChange(
ToggleScheduleEvent event, Emitter<WaterHeaterState> emit) async {
try { try {
emit(WHLoadingState()); emit(WHLoadingState());
final response = await DevicesAPI.changeSchedule( final response = await DevicesAPI.changeSchedule(
@ -284,7 +308,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
Future deleteSchedule(DeleteScheduleEvent event, Emitter<WaterHeaterState> emit) async { Future deleteSchedule(
DeleteScheduleEvent event, Emitter<WaterHeaterState> emit) async {
try { try {
emit(WHLoadingState()); emit(WHLoadingState());
final response = await DevicesAPI.deleteSchedule( final response = await DevicesAPI.deleteSchedule(
@ -303,7 +328,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
void _toggleCreateCirculate(ToggleCreateCirculate event, Emitter<WaterHeaterState> emit) { void _toggleCreateCirculate(
ToggleCreateCirculate event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState()); emit(WHLoadingState());
createCirculate = !createCirculate; createCirculate = !createCirculate;
selectedDays.clear(); selectedDays.clear();
@ -311,13 +337,15 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
emit(UpdateCreateScheduleState(createCirculate)); emit(UpdateCreateScheduleState(createCirculate));
} }
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<WaterHeaterState> emit) { void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState()); emit(WHLoadingState());
selectedTabIndex = event.index; selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex)); emit(ChangeSlidingSegmentState(value: selectedTabIndex));
} }
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<WaterHeaterState> emit) { void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<WaterHeaterState> emit) {
emit(WHLoadingState()); emit(WHLoadingState());
createSchedule = !createSchedule; createSchedule = !createSchedule;
selectedDays.clear(); selectedDays.clear();
@ -366,8 +394,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
List<GroupWHModel> groupWaterHeaterList = []; List<GroupWHModel> groupWaterHeaterList = [];
bool allSwitchesOn = true; bool allSwitchesOn = true;
void _changeFirstWizardSwitch( void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
ChangeFirstWizardSwitchStatusEvent event, Emitter<WaterHeaterState> emit) async { Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus)); emit(LoadingNewSate(whModel: deviceStatus));
try { try {
bool allSwitchesValue = true; bool allSwitchesValue = true;
@ -379,7 +407,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
allSwitchesValue = false; allSwitchesValue = false;
} }
}); });
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: allSwitchesValue)); emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -394,7 +423,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
void _fetchWHWizardStatus(InitialWizardEvent event, Emitter<WaterHeaterState> emit) async { void _fetchWHWizardStatus(
InitialWizardEvent event, Emitter<WaterHeaterState> emit) async {
emit(WHLoadingState()); emit(WHLoadingState());
try { try {
devicesList = []; devicesList = [];
@ -404,7 +434,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
HomeCubit.getInstance().selectedSpace?.id ?? '', 'WH'); HomeCubit.getInstance().selectedSpace?.id ?? '', 'WH');
for (int i = 0; i < devicesList.length; i++) { for (int i = 0; i < devicesList.length; i++) {
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = []; List<StatusModel> statusModelList = [];
for (var status in response['status']) { for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status)); statusModelList.add(StatusModel.fromJson(status));
@ -426,23 +457,27 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
return true; return true;
}); });
} }
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: allSwitchesOn)); emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: allSwitchesOn));
} catch (e) { } catch (e) {
// emit(FailedState(error: e.toString())); // emit(FailedState(error: e.toString()));
return; return;
} }
} }
void _groupAllOn(GroupAllOnEvent event, Emitter<WaterHeaterState> emit) async { void _groupAllOn(
GroupAllOnEvent event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus)); emit(LoadingNewSate(whModel: deviceStatus));
try { try {
for (int i = 0; i < groupWaterHeaterList.length; i++) { for (int i = 0; i < groupWaterHeaterList.length; i++) {
groupWaterHeaterList[i].firstSwitch = true; groupWaterHeaterList[i].firstSwitch = true;
} }
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: true)); emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: true));
List<String> allDeviceIds = groupWaterHeaterList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',
@ -460,15 +495,18 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
void _groupAllOff(GroupAllOffEvent event, Emitter<WaterHeaterState> emit) async { void _groupAllOff(
GroupAllOffEvent event, Emitter<WaterHeaterState> emit) async {
emit(LoadingNewSate(whModel: deviceStatus)); emit(LoadingNewSate(whModel: deviceStatus));
try { try {
for (int i = 0; i < groupWaterHeaterList.length; i++) { for (int i = 0; i < groupWaterHeaterList.length; i++) {
groupWaterHeaterList[i].firstSwitch = false; groupWaterHeaterList[i].firstSwitch = false;
} }
emit(UpdateGroupState(twoGangList: groupWaterHeaterList, allSwitches: false)); emit(UpdateGroupState(
twoGangList: groupWaterHeaterList, allSwitches: false));
List<String> allDeviceIds = groupWaterHeaterList.map((device) => device.deviceId).toList(); List<String> allDeviceIds =
groupWaterHeaterList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController( final response = await DevicesAPI.deviceBatchController(
code: 'switch_1', code: 'switch_1',

View File

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/water_leak_bloc/water_leak_event.dart'; import 'package:syncrow_app/features/devices/bloc/water_leak_bloc/water_leak_event.dart';
import 'package:syncrow_app/features/devices/bloc/water_leak_bloc/water_leak_state.dart'; import 'package:syncrow_app/features/devices/bloc/water_leak_bloc/water_leak_state.dart';
@ -21,7 +20,6 @@ class WaterLeakBloc extends Bloc<WaterLeakEvent, WaterLeakState> {
on<ToggleClosingReminderEvent>(_toggleClosingReminder); on<ToggleClosingReminderEvent>(_toggleClosingReminder);
on<ToggleWaterLeakAlarmEvent>(_toggleWaterLeakAlarm); on<ToggleWaterLeakAlarmEvent>(_toggleWaterLeakAlarm);
} }
Timer? _timer;
bool lowBattery = false; bool lowBattery = false;
bool closingReminder = false; bool closingReminder = false;
bool waterAlarm = false; bool waterAlarm = false;
@ -134,32 +132,42 @@ class WaterLeakBloc extends Bloc<WaterLeakEvent, WaterLeakState> {
emit(WaterLeakFailedState(errorMessage: errorMessage)); emit(WaterLeakFailedState(errorMessage: errorMessage));
} }
} }
// Timer? _timer;
// StreamSubscription<DatabaseEvent>? _streamSubscription;
// void _listenToChanges() {
// try {
// _streamSubscription?.cancel();
// DatabaseReference ref =
// FirebaseDatabase.instance.ref('device-status/$WLId');
// Stream<DatabaseEvent> stream = ref.onValue;
_listenToChanges() { // _streamSubscription = stream.listen((DatabaseEvent event) async {
try { // if (_timer != null) {
DatabaseReference ref = // await Future.delayed(const Duration(seconds: 2));
FirebaseDatabase.instance.ref('device-status/$WLId'); // }
Stream<DatabaseEvent> stream = ref.onValue; // 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 = WaterLeakModel.fromJson(statusList);
// if (!isClosed) {
// add(
// WaterLeakSwitch(switchD: deviceStatus.waterContactState),
// );
// }
// });
// } catch (_) {}
// }
stream.listen((DatabaseEvent event) async { // @override
if (_timer != null) { // Future<void> close() async {
await Future.delayed(const Duration(seconds: 2)); // _streamSubscription?.cancel();
} // _streamSubscription = null;
Map<dynamic, dynamic> usersMap = // return super.close();
event.snapshot.value as Map<dynamic, dynamic>; // }
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: true));
});
deviceStatus = WaterLeakModel.fromJson(statusList);
if (!isClosed) {
add(
WaterLeakSwitch(switchD: deviceStatus.waterContactState),
);
}
});
} catch (_) {}
}
} }

View File

@ -27,24 +27,24 @@ class AcStatusModel {
} }
factory AcStatusModel.fromJson(String id, List<StatusModel> jsonList) { factory AcStatusModel.fromJson(String id, List<StatusModel> jsonList) {
late bool _acSwitch; bool _acSwitch = false;
late String _mode; String _mode = '';
late int _tempSet; int _tempSet = 210;
late int _currentTemp; int _currentTemp = 210;
late String _fanSpeeds; String _fanSpeeds = '';
late int _countdown1; int _countdown1 = 0;
late bool _childLock; bool _childLock = false;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch') { if (jsonList[i].code == 'switch') {
_acSwitch = jsonList[i].value ?? false; _acSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'mode') { } else if (jsonList[i].code == 'mode') {
_mode = jsonList[i].value ?? TempModes.cold; _mode = jsonList[i].value ?? '';
} else if (jsonList[i].code == 'temp_set') { } else if (jsonList[i].code == 'temp_set') {
_tempSet = jsonList[i].value ?? 210; _tempSet = jsonList[i].value ?? 210;
} else if (jsonList[i].code == 'temp_current') { } else if (jsonList[i].code == 'temp_current') {
_currentTemp = jsonList[i].value ?? 210; _currentTemp = jsonList[i].value ?? 210;
} else if (jsonList[i].code == 'level') { } else if (jsonList[i].code == 'level') {
_fanSpeeds = jsonList[i].value ?? 210; _fanSpeeds = jsonList[i].value ?? '';
} else if (jsonList[i].code == 'child_lock') { } else if (jsonList[i].code == 'child_lock') {
_childLock = jsonList[i].value ?? false; _childLock = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_time') { } else if (jsonList[i].code == 'countdown_time') {

View File

@ -23,9 +23,9 @@ class CeilingSensorModel {
required this.bodyMovement}); required this.bodyMovement});
factory CeilingSensorModel.fromJson(List<StatusModel> jsonList) { factory CeilingSensorModel.fromJson(List<StatusModel> jsonList) {
late String _presenceState; String _presenceState = 'none';
late int _sensitivity; int _sensitivity = 1;
late String _checkingResult; String _checkingResult = '';
int _presenceRange = 1; int _presenceRange = 1;
int _sportsPara = 1; int _sportsPara = 1;
int _moving_max_dis = 0; int _moving_max_dis = 0;

View File

@ -10,11 +10,11 @@ class CurtainModel {
}); });
factory CurtainModel.fromJson(List<StatusModel> jsonList) { factory CurtainModel.fromJson(List<StatusModel> jsonList) {
late String _control; String _control = '';
late int _percent; int _percent = 0;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'control') { if (jsonList[i].code == 'control') {
_control = jsonList[i].value ?? false; _control = jsonList[i].value ?? '';
} }
if (jsonList[i].code == 'percent_control') { if (jsonList[i].code == 'percent_control') {
_percent = jsonList[i].value ?? 0; _percent = jsonList[i].value ?? 0;

View File

@ -1,5 +1,3 @@
import 'dart:convert';
class DeviceInfoModel { class DeviceInfoModel {
final int activeTime; final int activeTime;
final String category; final String category;

View File

@ -10,6 +10,9 @@ class DeviceModel {
String? model; String? model;
String? name; String? name;
String? icon; String? icon;
String? categoryName;
bool? toggleStatus = false;
String? type; String? type;
bool? isOnline; bool? isOnline;
List<StatusModel> status = []; List<StatusModel> status = [];
@ -21,6 +24,8 @@ class DeviceModel {
DeviceType? productType; DeviceType? productType;
bool isSelected = false; bool isSelected = false;
late List<FunctionModel> functions; late List<FunctionModel> functions;
DeviceSubspace? subspace;
DeviceModel( DeviceModel(
{this.activeTime, {this.activeTime,
this.productUuid, this.productUuid,
@ -34,6 +39,9 @@ class DeviceModel {
this.updateTime, this.updateTime,
this.uuid, this.uuid,
this.productType, this.productType,
this.categoryName,
this.subspace,
this.toggleStatus,
this.icon, this.icon,
this.type}) { this.type}) {
functions = getFunctions(productType!); functions = getFunctions(productType!);
@ -87,23 +95,74 @@ class DeviceModel {
} else { } else {
tempIcon = Assets.assetsIconsLogo; tempIcon = Assets.assetsIconsLogo;
} }
// Step 1: Parse `status` as before
final statusList = (json['status'] as List<dynamic>?)
?.map((st) => StatusModel.fromJson(st as Map<String, dynamic>))
.toList();
// Step 2: Check whether ANY status means "off"
final anyOff = statusList?.any((s) {
final code = s.code;
if (code == null) return false;
// 1) Handle "switch" or "switch_x"
if (code == 'switch' || code.startsWith('switch_')) {
// If it's false, we consider that "off"
return s.value == false;
}
// 2) If code == "control" and value == "stop", consider "off"
if (s.value == 'open') {
return true;
}
// 3) If code == "percent_control" and value == 0, maybe "off"
if (code == 'percent_control' && s.value == 0) {
return true;
}
// Add more conditions for other codes as needed
// Default: if none of the above apply, it's not "off"
return false;
});
// Step 3: Decide final toggleStatus (true = fully "on", false = partially/fully "off")
bool computedToggleStatus = !(anyOff ?? false);
return DeviceModel( return DeviceModel(
icon: tempIcon, icon: tempIcon,
activeTime: json['activeTime'], activeTime: json['activeTime'],
// id: json['id'], categoryName: json['categoryName'],
localKey: json['localKey'], localKey: json['localKey'],
model: json['model'], model: json['model'],
name: json['name'], name: json['name'],
isOnline: json['online'], isOnline: json['online'],
productName: json['productName'], productName: json['productName'],
timeZone: json['timeZone'], timeZone: json['timeZone'],
updateTime: json['updateTime'], updateTime: json['updateTime'],
uuid: json['uuid'], uuid: json['uuid'],
productType: type, productType: type,
type: json['productType'], type: json['productType'],
status: [],
productUuid: json['productUuid']); // Use the newly computed toggleStatus:
toggleStatus: computedToggleStatus,
// Or if you prefer to use the value returned by the backend when available:
// toggleStatus: json['toggleStatus'] ?? computedToggleStatus,
status: statusList ?? [],
subspace: json['subspace'] != null
? DeviceSubspace.fromJson(json['subspace'])
: DeviceSubspace(
createdAt: null,
disabled: false,
subspaceName: '',
updatedAt: null,
uuid: '',
),
productUuid: json['productUuid'],
);
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -118,9 +177,50 @@ class DeviceModel {
'updateTime': updateTime, 'updateTime': updateTime,
'uuid': uuid, 'uuid': uuid,
'productType': productType, 'productType': productType,
'subspace': subspace?.toJson(), // serialize subspace
}; };
} }
List<FunctionModel> getFunctions(DeviceType type) => List<FunctionModel> getFunctions(DeviceType type) =>
devicesFunctionsMap[productType] ?? []; devicesFunctionsMap[productType] ?? [];
} }
class DeviceSubspace {
String? uuid;
DateTime? createdAt;
DateTime? updatedAt;
String? subspaceName;
bool? disabled;
DeviceSubspace({
this.uuid,
this.createdAt,
this.updatedAt,
this.subspaceName,
this.disabled,
});
factory DeviceSubspace.fromJson(Map<String, dynamic> json) {
return DeviceSubspace(
uuid: json['uuid'],
createdAt: json['createdAt'] != null
? DateTime.tryParse(json['createdAt'])
: null,
updatedAt: json['updatedAt'] != null
? DateTime.tryParse(json['updatedAt'])
: null,
subspaceName: json['subspaceName'],
disabled: json['disabled'],
);
}
Map<String, dynamic> toJson() {
return {
'uuid': uuid,
'createdAt': createdAt?.toIso8601String(),
'updatedAt': updatedAt?.toIso8601String(),
'subspaceName': subspaceName,
'disabled': disabled,
};
}
}

View File

@ -1,27 +1,22 @@
import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/features/devices/model/status_model.dart';
class DoorSensorModel { class DoorSensorModel {
bool doorContactState; bool doorContactState;
int batteryPercentage; int batteryPercentage;
DoorSensorModel( DoorSensorModel({
{required this.doorContactState, required this.doorContactState,
required this.batteryPercentage, required this.batteryPercentage,
}); });
factory DoorSensorModel.fromJson(List<StatusModel> jsonList) { factory DoorSensorModel.fromJson(List<StatusModel> jsonList) {
late bool _doorContactState; bool _doorContactState = false;
late int _batteryPercentage; int _batteryPercentage = 0;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'doorcontact_state') { if (jsonList[i].code == 'doorcontact_state') {
_doorContactState = jsonList[i].value ?? false; _doorContactState = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'battery_percentage') { } else if (jsonList[i].code == 'battery_percentage') {
_batteryPercentage = jsonList[i].value ?? 0; _batteryPercentage = jsonList[i].value ?? 0;
} }
} }

View File

@ -24,15 +24,15 @@ class GarageDoorModel {
}); });
factory GarageDoorModel.fromJson(List<StatusModel> jsonList) { factory GarageDoorModel.fromJson(List<StatusModel> jsonList) {
late bool _switch1 = false; bool _switch1 = false;
late bool _doorContactState = false; bool _doorContactState = false;
late int _countdown1 = 0; int _countdown1 = 0;
late int _countdownAlarm = 0; int _countdownAlarm = 0;
late String _doorControl1 = "closed"; String _doorControl1 = "closed";
late bool _voiceControl1 = false; bool _voiceControl1 = false;
late String _doorState1 = "closed"; String _doorState1 = "closed";
late int _batteryPercentage = 0; int _batteryPercentage = 0;
late int _tr_timecon = 0; int _tr_timecon = 0;
for (var status in jsonList) { for (var status in jsonList) {
switch (status.code) { switch (status.code) {

View File

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

View File

@ -1,5 +1,3 @@
import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
@ -15,15 +13,14 @@ class OneTouchModel {
required this.firstCountDown, required this.firstCountDown,
required this.light_mode, required this.light_mode,
required this.relay, required this.relay,
required this.relay_status_1 required this.relay_status_1});
});
factory OneTouchModel.fromJson(List<StatusModel> jsonList) { factory OneTouchModel.fromJson(List<StatusModel> jsonList) {
late bool _switch; bool _switch = false;
late int _count; int _count = 0;
late String _relay; String _relay = '';
late String _light_mode; String _light_mode = '';
late String relay_status_1; String relay_status_1 = '';
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') { if (jsonList[i].code == 'switch_1') {
@ -41,10 +38,8 @@ class OneTouchModel {
return OneTouchModel( return OneTouchModel(
firstSwitch: _switch, firstSwitch: _switch,
firstCountDown: _count, firstCountDown: _count,
light_mode: lightStatusExtension.fromString(_light_mode) , light_mode: lightStatusExtension.fromString(_light_mode),
relay: StatusExtension.fromString(_relay ) , relay: StatusExtension.fromString(_relay),
relay_status_1: StatusExtension.fromString(relay_status_1 ) relay_status_1: StatusExtension.fromString(relay_status_1));
);
} }
} }

View File

@ -22,14 +22,14 @@ class SixSceneModel {
}); });
factory SixSceneModel.fromJson(List<StatusModel> jsonList) { factory SixSceneModel.fromJson(List<StatusModel> jsonList) {
late dynamic _scene_1; dynamic _scene_1 = '';
late dynamic _scene_2; dynamic _scene_2 = '';
late dynamic _scene_3; dynamic _scene_3 = '';
late dynamic _scene_4; dynamic _scene_4 = '';
late dynamic _scene_5; dynamic _scene_5 = '';
late dynamic _scene_6; dynamic _scene_6 = '';
late dynamic _scene_id_group_id; dynamic _scene_id_group_id = 0;
late dynamic _switch_backlight; dynamic _switch_backlight = false;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'scene_1') { if (jsonList[i].code == 'scene_1') {

View File

@ -39,23 +39,23 @@ class SmartDoorModel {
required this.normalOpenSwitch}); required this.normalOpenSwitch});
factory SmartDoorModel.fromJson(List<StatusModel> jsonList) { factory SmartDoorModel.fromJson(List<StatusModel> jsonList) {
late int _unlockFingerprint; int _unlockFingerprint = 0;
late int _unlockPassword; int _unlockPassword = 0;
late int _unlockTemporary; int _unlockTemporary = 0;
late int _unlockCard; int _unlockCard = 0;
late String _unlockAlarm; String _unlockAlarm = '';
late int _unlockRequest; int _unlockRequest = 0;
late int _residualElectricity; int _residualElectricity = 0;
late bool _reverseLock; bool _reverseLock = false;
late int _unlockApp; int _unlockApp = 0;
late bool _hijack; bool _hijack = false;
late bool _doorbell; bool _doorbell = false;
late String _unlockOfflinePd; String _unlockOfflinePd = '';
late String _unlockOfflineClear; String _unlockOfflineClear = '';
late String _unlockDoubleKit; String _unlockDoubleKit = '';
late String _remoteNoPdSetkey; String _remoteNoPdSetkey = '';
late String _remoteNoDpKey; String _remoteNoDpKey = '';
late bool _normalOpenSwitch; bool _normalOpenSwitch = false;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'unlock_fingerprint') { if (jsonList[i].code == 'unlock_fingerprint') {

View File

@ -10,8 +10,8 @@ class SosModel {
}); });
factory SosModel.fromJson(List<StatusModel> jsonList) { factory SosModel.fromJson(List<StatusModel> jsonList) {
late String _sosContactState; String _sosContactState = '';
late int _batteryPercentage; int _batteryPercentage = 0;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'sos') { if (jsonList[i].code == 'sos') {

View File

@ -9,17 +9,18 @@ class WallSensorModel {
int currentDistance; int currentDistance;
int illuminance; int illuminance;
bool indicator; bool indicator;
int noOneTime;
WallSensorModel({ WallSensorModel(
required this.presenceState, {required this.presenceState,
required this.farDetection, required this.farDetection,
required this.presenceTime, required this.presenceTime,
required this.motionSensitivity, required this.motionSensitivity,
required this.motionlessSensitivity, required this.motionlessSensitivity,
required this.currentDistance, required this.currentDistance,
required this.illuminance, required this.illuminance,
required this.indicator, required this.indicator,
}); required this.noOneTime});
factory WallSensorModel.fromJson(List<StatusModel> jsonList) { factory WallSensorModel.fromJson(List<StatusModel> jsonList) {
late String _presenceState; late String _presenceState;
@ -30,6 +31,7 @@ class WallSensorModel {
late int _currentDistance; late int _currentDistance;
late int _illuminance; late int _illuminance;
late bool _indicator; late bool _indicator;
late int _noOneTime;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'presence_state') { if (jsonList[i].code == 'presence_state') {
@ -48,6 +50,8 @@ class WallSensorModel {
_illuminance = jsonList[i].value ?? 0; _illuminance = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'indicator') { } else if (jsonList[i].code == 'indicator') {
_indicator = jsonList[i].value ?? false; _indicator = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'no_one_time') {
_noOneTime = jsonList[i].value ?? 0;
} }
} }
return WallSensorModel( return WallSensorModel(
@ -58,6 +62,7 @@ class WallSensorModel {
motionlessSensitivity: _motionlessSensitivity, motionlessSensitivity: _motionlessSensitivity,
currentDistance: _currentDistance, currentDistance: _currentDistance,
illuminance: _illuminance, illuminance: _illuminance,
indicator: _indicator); indicator: _indicator,
noOneTime: _noOneTime);
} }
} }

View File

@ -38,8 +38,10 @@ class SettingProfilePage extends StatelessWidget {
final _bloc = BlocProvider.of<DeviceSettingBloc>(context); final _bloc = BlocProvider.of<DeviceSettingBloc>(context);
return state is DeviceSettingLoadingState return state is DeviceSettingLoadingState
? const Center( ? const Center(
child: child: DefaultContainer(
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), width: 50,
height: 50,
child: CircularProgressIndicator()),
) )
: RefreshIndicator( : RefreshIndicator(
onRefresh: () async { onRefresh: () async {
@ -55,15 +57,18 @@ class SettingProfilePage extends StatelessWidget {
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.sosHomeIcon, Assets.sosHomeIcon,
fit: BoxFit.fitHeight, fit: BoxFit.fitHeight,
height: MediaQuery.of(context).size.height * 0.13, height:
MediaQuery.of(context).size.height * 0.13,
)) ))
: CircleAvatar( : CircleAvatar(
radius: 55, radius: 55,
backgroundColor: ColorsManager.graysColor, backgroundColor: ColorsManager.graysColor,
child: ClipOval( child: ClipOval(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Center( Center(
child: SvgPicture.asset( child: SvgPicture.asset(
@ -71,7 +76,10 @@ class SettingProfilePage extends StatelessWidget {
? Assets.fourSceneIcon ? Assets.fourSceneIcon
: Assets.sixSceneIcon, : Assets.sixSceneIcon,
fit: BoxFit.contain, fit: BoxFit.contain,
height: MediaQuery.of(context).size.height * 0.08, height: MediaQuery.of(context)
.size
.height *
0.08,
), ),
), ),
], ],
@ -89,7 +97,8 @@ class SettingProfilePage extends StatelessWidget {
children: [ children: [
IntrinsicWidth( IntrinsicWidth(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 200), constraints:
const BoxConstraints(maxWidth: 200),
child: TextFormField( child: TextFormField(
maxLength: 30, maxLength: 30,
style: const TextStyle( style: const TextStyle(
@ -122,7 +131,8 @@ class SettingProfilePage extends StatelessWidget {
Assets.sosEditProfile, Assets.sosEditProfile,
color: Colors.grey, color: Colors.grey,
fit: BoxFit.contain, fit: BoxFit.contain,
height: MediaQuery.of(context).size.height * 0.02, height: MediaQuery.of(context).size.height *
0.02,
), ),
), ),
), ),
@ -141,15 +151,17 @@ class SettingProfilePage extends StatelessWidget {
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
child: InkWell( child: InkWell(
onTap: () async { onTap: () async {
bool? val = await Navigator.of(context).push( if (HomeCubit.visitorPasswordManagement) {
MaterialPageRoute( bool? val = await Navigator.of(context).push(
builder: (context) => LocationSettingPage( MaterialPageRoute(
space: spaces!.first, builder: (context) => LocationSettingPage(
deviceId: device?.uuid ?? '', space: spaces!.first,
)), deviceId: device?.uuid ?? '',
); )),
if (val != null && val == true) { );
_bloc.add(const DeviceSettingInitialInfo()); if (val != null && val == true) {
_bloc.add(const DeviceSettingInitialInfo());
}
} }
}, },
child: Row( child: Row(
@ -162,7 +174,8 @@ class SettingProfilePage extends StatelessWidget {
children: [ children: [
SizedBox( SizedBox(
child: BodyMedium( child: BodyMedium(
text: _bloc.deviceInfo.subspace.subspaceName, text: _bloc
.deviceInfo.subspace.subspaceName,
fontColor: ColorsManager.textGray, fontColor: ColorsManager.textGray,
), ),
), ),

View File

@ -1,9 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart'; import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart'; import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart'; import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_controls.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_controls.dart';
@ -71,6 +73,7 @@ class AcInterface extends StatelessWidget {
onTap: () { onTap: () {
BlocProvider.of<ACsBloc>(context) BlocProvider.of<ACsBloc>(context)
.add(AcSwitch(acSwitch: statusModel.acSwitch)); .add(AcSwitch(acSwitch: statusModel.acSwitch));
}, },
child: SvgPicture.asset(Assets.acSwitchIcon)) child: SvgPicture.asset(Assets.acSwitchIcon))
], ],

View File

@ -43,6 +43,7 @@ class AcInterfaceControls extends StatelessWidget {
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
AcTimerPage( AcTimerPage(
deviceStatus: deviceStatus,
device: deviceModel, device: deviceModel,
deviceCode: deviceModel.type!, deviceCode: deviceModel.type!,
switchCode: '', switchCode: '',

View File

@ -7,7 +7,7 @@ import 'package:syncrow_app/features/devices/bloc/6_scene_switch_bloc/6_scene_st
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart'; import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart'; import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/ACs/custom_halfhour_timer_picker.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/custom_halfhour_timer_picker.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
@ -20,10 +20,13 @@ class AcTimerPage extends StatelessWidget {
final DeviceModel device; final DeviceModel device;
final String deviceCode; final String deviceCode;
final String switchCode; final String switchCode;
final AcStatusModel deviceStatus;
const AcTimerPage( const AcTimerPage(
{required this.device, {required this.device,
required this.deviceCode, required this.deviceCode,
required this.switchCode, required this.switchCode,
required this.deviceStatus,
super.key}); super.key});
@override @override
@ -37,27 +40,24 @@ class AcTimerPage extends StatelessWidget {
create: (context) => ACsBloc(acId: device.uuid ?? ''), create: (context) => ACsBloc(acId: device.uuid ?? ''),
child: BlocBuilder<ACsBloc, AcsState>( child: BlocBuilder<ACsBloc, AcsState>(
builder: (context, state) { builder: (context, state) {
final oneGangBloc = BlocProvider.of<ACsBloc>(context); final acBloc = BlocProvider.of<ACsBloc>(context);
Duration duration = Duration.zero; Duration duration = Duration.zero;
int selectedValue = 0; int selectedValue = 0;
int countNum = 0; int countNum = 0;
if (state is UpdateTimerState) { if (state is AcsInitialState) {
acBloc.add(GetCounterEvent(deviceCode: deviceCode));
} else if (state is UpdateTimerState) {
countNum = state.seconds; countNum = state.seconds;
} else if (state is TimerRunInProgress) { } else if (state is TimerRunInProgress) {
countNum = state.remainingTime; countNum = state.remainingTime;
} else if (state is TimerRunComplete) { } else if (state is TimerRunComplete) {
countNum = 0; countNum = 0;
} }
// else if (state is LoadingNewSate) {
// countNum = 0;
// }
return PopScope( return PopScope(
canPop: false, canPop: false,
onPopInvoked: (didPop) { onPopInvoked: (didPop) {
if (!didPop) { if (!didPop) {
oneGangBloc.add(OnClose()); acBloc.add(OnClose());
Navigator.pop(context); Navigator.pop(context);
} }
}, },
@ -90,7 +90,7 @@ class AcTimerPage extends StatelessWidget {
), ),
), ),
Center( Center(
child: Container( child: SizedBox(
child: Column( child: Column(
mainAxisAlignment: mainAxisAlignment:
MainAxisAlignment.center, MainAxisAlignment.center,
@ -102,7 +102,7 @@ class AcTimerPage extends StatelessWidget {
.slidingBlueColor, .slidingBlueColor,
fontSize: 40, fontSize: 40,
) )
: Container( : SizedBox(
child: CustomHalfHourPicker( child: CustomHalfHourPicker(
onValueChanged: (value) { onValueChanged: (value) {
selectedValue = selectedValue =
@ -120,8 +120,6 @@ class AcTimerPage extends StatelessWidget {
countNum = countNum =
duration.inSeconds; duration.inSeconds;
} }
print(
"Selected Value: $selectedValue, Duration: $duration");
}, },
), ),
), ),
@ -131,12 +129,14 @@ class AcTimerPage extends StatelessWidget {
return; return;
} }
if (countNum > 0) { if (countNum > 0) {
oneGangBloc.add(SetCounterValue( acBloc.add(SetCounterValue(
seconds: countNum, seconds: countNum,
deviceCode:'countdown_time', deviceCode:
'countdown_time',
duration: selectedValue)); duration: selectedValue));
} else if (duration != Duration.zero) { } else if (duration !=
oneGangBloc.add(SetCounterValue( Duration.zero) {
acBloc.add(SetCounterValue(
seconds: 0, seconds: 0,
deviceCode: deviceCode:
'countdown_time', 'countdown_time',

View File

@ -31,7 +31,7 @@ class ACsList extends StatelessWidget {
List<DeviceModel> devicesList = []; List<DeviceModel> devicesList = [];
bool allOn = false; bool allOn = false;
bool allTempSame = false; bool allTempSame = false;
int temperature = 20; int temperature = 250;
if (state is GetAllAcsStatusState) { if (state is GetAllAcsStatusState) {
devicesStatuesList = state.allAcsStatues; devicesStatuesList = state.allAcsStatues;
devicesList = state.allAcs; devicesList = state.allAcs;

View File

@ -22,9 +22,8 @@ class ACsView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
print("ACsView deviceModel UUID: ${deviceModel?.uuid}");
return BlocProvider( return BlocProvider(
create: (context) => ACsBloc(acId: deviceModel?.uuid ?? '') create: (context) => ACsBloc(acId: deviceModel?.uuid ?? '')
..add(AcsInitial(allAcs: deviceModel != null ? false : true)), ..add(AcsInitial(allAcs: deviceModel != null ? false : true)),
child: BlocBuilder<ACsBloc, AcsState>( child: BlocBuilder<ACsBloc, AcsState>(
@ -40,6 +39,7 @@ class ACsView extends StatelessWidget {
extendBody: true, extendBody: true,
appBar: deviceModel != null appBar: deviceModel != null
? DeviceAppbar( ? DeviceAppbar(
value: true,
deviceName: deviceModel!.name!, deviceName: deviceModel!.name!,
deviceUuid: deviceModel!.uuid!, deviceUuid: deviceModel!.uuid!,
) )

View File

@ -0,0 +1,110 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class AllDevices extends StatefulWidget {
const AllDevices({super.key, required this.allDevices});
final List<DeviceModel> allDevices;
@override
_AllDevicesState createState() => _AllDevicesState();
}
class _AllDevicesState extends State<AllDevices> {
final TextEditingController _searchController = TextEditingController();
List<DeviceModel> _filteredDevices = [];
@override
void initState() {
super.initState();
_filteredDevices = widget.allDevices ?? [];
_searchController.addListener(_filterDevices);
}
@override
void dispose() {
_searchController.removeListener(_filterDevices);
_searchController.dispose();
super.dispose();
}
void _filterDevices() {
final query = _searchController.text.toLowerCase();
setState(() {
_filteredDevices = widget.allDevices!
.where((device) => device.name!.toLowerCase().contains(query))
.toList();
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
if (widget.allDevices.isNotEmpty)
TextFormField(
controller: _searchController,
decoration: InputDecoration(
hintText: 'Search',
hintStyle: const TextStyle(
color: ColorsManager.textGray,
fontSize: 16,
fontWeight: FontWeight.w400),
prefixIcon: Container(
padding: const EdgeInsets.all(5.0),
margin: const EdgeInsets.all(10.0),
child: SvgPicture.asset(
Assets.searchIcon,
fit: BoxFit.contain,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
_filteredDevices.isNotEmpty
? Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1.5,
),
padding: const EdgeInsets.only(top: 10),
itemCount: _filteredDevices.length,
itemBuilder: (context, index) {
return RoomPageSwitch(
allDevices: _filteredDevices,
isAllDevices: true,
device: _filteredDevices[index]);
},
),
)
: widget.allDevices.isNotEmpty
? const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
'No Results Found',
style: TextStyle(
color: ColorsManager.grayColor,
fontSize: 14,
fontWeight: FontWeight.w400),
)),
],
),
)
: const SizedBox(),
],
);
}
}

View File

@ -250,7 +250,9 @@ class CeilingSensorInterface extends StatelessWidget {
), ),
] else if (button['title'] == 'Space Type') ...[ ] else if (button['title'] == 'Space Type') ...[
Text( Text(
model.spaceType.name.toString(), model.spaceType.name.toString() == "none"
? "Office"
: model.spaceType.name.toString(),
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
), ),
] else ...[ ] else ...[
@ -299,7 +301,13 @@ class CeilingSensorInterface extends StatelessWidget {
); );
if (result != null) { if (result != null) {
bloc.add(ChangeValueEvent( bloc.add(ChangeValueEvent(
type: title.toString(), value: result, code: 'nobody_time')); type: title.toString(),
value: result
.toString()
.toLowerCase()
.replaceAll('sec', 's')
.replaceAll('1hr', '1hour'),
code: 'nobody_time'));
} }
} else if (title == 'Maximum Distance') { } else if (title == 'Maximum Distance') {
final result = await _showDialog( final result = await _showDialog(
@ -324,7 +332,7 @@ class CeilingSensorInterface extends StatelessWidget {
title: title.toString(), title: title.toString(),
sensor: ceilingSensor, sensor: ceilingSensor,
value: model.sensitivity, value: model.sensitivity,
min: 0, min: 1,
max: 10, max: 10,
)); ));
if (result != null) { if (result != null) {
@ -336,7 +344,7 @@ class CeilingSensorInterface extends StatelessWidget {
context, context,
MaterialPageRoute(builder: (context) => const CeilingHelpDescription()), MaterialPageRoute(builder: (context) => const CeilingHelpDescription()),
); );
} else if (title == 'Induction History') { } else if (title == 'Presence Record') {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -385,7 +393,7 @@ class CeilingSensorInterface extends StatelessWidget {
'val': nobodyTimeVal, 'val': nobodyTimeVal,
}, },
{ {
'title': 'Induction History', 'title': 'Presence Record',
'icon': Assets.assetsIconsPresenceSensorAssetsInductionRecording, 'icon': Assets.assetsIconsPresenceSensorAssetsInductionRecording,
'page': null, 'page': null,
'withArrow': false, 'withArrow': false,

View File

@ -31,12 +31,12 @@ class MaxDistanceControl extends StatefulWidget {
} }
int _parseValue(String value) { int _parseValue(String value) {
if (value.endsWith('sec')) { if (value.endsWith('s')) {
return int.parse(value.replaceAll('sec', '').trim()); return int.parse(value.replaceAll('s', '').trim());
} else if (value.endsWith('min')) { } else if (value.endsWith('min')) {
return int.parse(value.replaceAll('min', '').trim()) * 60; return int.parse(value.replaceAll('min', '').trim()) * 60;
} else if (value.endsWith('hr')) { } else if (value.endsWith('hour')) {
return int.parse(value.replaceAll('hr', '').trim()) * 3600; return int.parse(value.replaceAll('hour', '').trim()) * 3600;
} }
return 0; // Default to 0 if the format is unrecognized return 0; // Default to 0 if the format is unrecognized
} }
@ -58,7 +58,7 @@ class MaxDistanceControlState extends State<MaxDistanceControl> {
String _formatLabel(double seconds) { String _formatLabel(double seconds) {
if (seconds == 0) return 'None'; if (seconds == 0) return 'None';
if (seconds < 60) return '${seconds.toInt()}sec'; if (seconds < 60) return '${seconds.toInt()}s';
if (seconds < 3600) { if (seconds < 3600) {
final minutes = (seconds / 60).round(); final minutes = (seconds / 60).round();
return '${minutes}min'; return '${minutes}min';
@ -90,7 +90,6 @@ class MaxDistanceControlState extends State<MaxDistanceControl> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final double currentSeconds = _stepValues[_currentIndex]; final double currentSeconds = _stepValues[_currentIndex];
return Dialog( return Dialog(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -128,7 +127,9 @@ class MaxDistanceControlState extends State<MaxDistanceControl> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
TitleMedium( TitleMedium(
text: _formatLabel(currentSeconds), text: _formatLabel(currentSeconds)
.replaceAll('1hr', '1hour')
.replaceAllMapped(RegExp(r's$'), (match) => 'sec'),
style: context.titleMedium.copyWith( style: context.titleMedium.copyWith(
color: Colors.black, color: Colors.black,
fontWeight: FontsManager.bold, fontWeight: FontsManager.bold,

View File

@ -90,9 +90,7 @@ class PresenceRecord extends StatelessWidget {
: Colors.grey, : Colors.grey,
), ),
title: Text( title: Text(
record.value == 'true' record.value.toString(),
? "Opened"
: "Closed",
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 18, fontSize: 18,

View File

@ -106,12 +106,11 @@ class _PresenceSpaceTypeDialogState extends State<PresenceSpaceTypeDialog> {
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: SvgPicture.asset( child: SvgPicture.asset(
icon, icon,
), ),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
title, title == "None" ? "Office" : title,
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodySmall .bodySmall

View File

@ -6,6 +6,7 @@ import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_event.dar
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart'; import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_buttons.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_buttons.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/default_scaffold.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
@ -33,11 +34,17 @@ class CurtainView extends StatelessWidget {
// blindHeight = state.blindHeight; // blindHeight = state.blindHeight;
} }
return DefaultScaffold( return DefaultScaffold(
appBar: DeviceAppbar(
deviceName: curtain!.name!,
deviceUuid: curtain!.uuid!,
),
title: curtain.name, title: curtain.name,
child: state is CurtainLoadingState child: state is CurtainLoadingState
? const Center( ? const Center(
child: child: DefaultContainer(
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), width: 50,
height: 50,
child: CircularProgressIndicator()),
) )
: RefreshIndicator( : RefreshIndicator(
onRefresh: () async { onRefresh: () async {
@ -62,37 +69,56 @@ class CurtainView extends StatelessWidget {
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
Assets.assetsIconsCurtainsIconCurtainHolder, Assets.assetsIconsCurtainsIconCurtainHolder,
width: MediaQuery.sizeOf(context).width * 0.75, width:
MediaQuery.sizeOf(context).width * 0.75,
), ),
SizedBox( SizedBox(
width: MediaQuery.sizeOf(context).width * 0.75, width:
MediaQuery.sizeOf(context).width * 0.75,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
SizedBox( SizedBox(
width: MediaQuery.sizeOf(context).width * 0.025, width:
MediaQuery.sizeOf(context).width *
0.025,
), ),
AnimatedContainer( AnimatedContainer(
duration: const Duration(milliseconds: 200), duration:
const Duration(milliseconds: 200),
curve: Curves.linear, curve: Curves.linear,
height: MediaQuery.sizeOf(context).height * 0.35, height: MediaQuery.sizeOf(context)
width: MediaQuery.sizeOf(context).width * 0.35, .height *
0.35,
width:
MediaQuery.sizeOf(context).width *
0.35,
child: Stack( child: Stack(
children: List.generate( children: List.generate(
4, 4,
(index) { (index) {
double spacing = curtainWidth / 7.5; double spacing =
double leftMostPosition = index * spacing; curtainWidth / 7.5;
double leftMostPosition =
index * spacing;
return AnimatedPositioned( return AnimatedPositioned(
duration: const Duration(milliseconds: 200), duration: const Duration(
milliseconds: 200),
curve: Curves.linear, curve: Curves.linear,
left: leftMostPosition, left: leftMostPosition,
child: SizedBox( child: SizedBox(
height: height: MediaQuery.sizeOf(
MediaQuery.sizeOf(context).height * 0.35, context)
width: MediaQuery.sizeOf(context).width * 0.08, .height *
0.35,
width: MediaQuery.sizeOf(
context)
.width *
0.08,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.assetsIconsCurtainsIconVerticalBlade, Assets
.assetsIconsCurtainsIconVerticalBlade,
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
), ),
@ -102,23 +128,37 @@ class CurtainView extends StatelessWidget {
), ),
), ),
AnimatedContainer( AnimatedContainer(
duration: const Duration(milliseconds: 200), duration:
const Duration(milliseconds: 200),
curve: Curves.linear, curve: Curves.linear,
height: MediaQuery.sizeOf(context).height * 0.35, height: MediaQuery.sizeOf(context)
width: MediaQuery.sizeOf(context).width * 0.35, .height *
0.35,
width:
MediaQuery.sizeOf(context).width *
0.35,
child: Stack( child: Stack(
children: List.generate( children: List.generate(
4, 4,
(index) { (index) {
double spacing = curtainWidth / 7.5; double spacing =
double rightMostPosition = index * spacing; curtainWidth / 7.5;
double rightMostPosition =
index * spacing;
return AnimatedPositioned( return AnimatedPositioned(
duration: const Duration(milliseconds: 200), duration: const Duration(
milliseconds: 200),
curve: Curves.linear, curve: Curves.linear,
right: rightMostPosition, right: rightMostPosition,
child: SizedBox( child: SizedBox(
height: MediaQuery.sizeOf(context).height * 0.35, height: MediaQuery.sizeOf(
width: MediaQuery.sizeOf(context).width * 0.08, context)
.height *
0.35,
width: MediaQuery.sizeOf(
context)
.width *
0.08,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.rightVerticalBlade, Assets.rightVerticalBlade,
fit: BoxFit.fill, fit: BoxFit.fill,
@ -130,7 +170,9 @@ class CurtainView extends StatelessWidget {
), ),
), ),
SizedBox( SizedBox(
width: MediaQuery.sizeOf(context).width * 0.025, width:
MediaQuery.sizeOf(context).width *
0.025,
), ),
], ],
), ),

View File

@ -1,3 +1,4 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -6,14 +7,27 @@ import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class DeviceAppbar extends StatelessWidget implements PreferredSizeWidget { class DeviceAppbar extends StatelessWidget implements PreferredSizeWidget {
final String deviceName; final String deviceName;
final String deviceUuid; final String deviceUuid;
final bool? value;
final double appBarHeight = 56.0; final double appBarHeight = 56.0;
final void Function()? onPressed; final void Function()? onPressed;
const DeviceAppbar( const DeviceAppbar(
{super.key, required this.deviceName, required this.deviceUuid, this.onPressed}); {super.key,
required this.deviceName,
this.value,
required this.deviceUuid,
this.onPressed});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AppBar( return AppBar(
leading: IconButton(
onPressed: () {
Navigator.of(context).pop(value ?? true);
},
icon: Icon(
Platform.isIOS ? Icons.arrow_back_ios : Icons.arrow_back,
)),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
centerTitle: true, centerTitle: true,
title: BodyLarge( title: BodyLarge(

View File

@ -3,10 +3,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/devices/view/widgets/all_devices.dart';
import 'package:syncrow_app/features/devices/view/widgets/room_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/room_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/rooms_slider.dart'; import 'package:syncrow_app/features/devices/view/widgets/rooms_slider.dart';
import 'package:syncrow_app/features/devices/view/widgets/wizard_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/wizard_page.dart';
import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/view/scene_view.dart'; import 'package:syncrow_app/features/scene/view/scene_view.dart';
import 'package:syncrow_app/features/shared_widgets/create_unit.dart'; import 'package:syncrow_app/features/shared_widgets/create_unit.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
@ -14,103 +14,120 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.da
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
class DevicesViewPage extends StatelessWidget {
const DevicesViewPage({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SceneBloc(), // Initialize your SceneBloc here
child: DevicesViewBody(),
);
}
}
class DevicesViewBody extends StatelessWidget { class DevicesViewBody extends StatelessWidget {
const DevicesViewBody({ const DevicesViewBody({super.key});
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<DevicesCubit, DevicesState>( return BlocBuilder<HomeCubit, HomeState>(
builder: (context, state) { builder: (context, homeState) {
if (state is DevicesLoading || final homeCubit = HomeCubit.getInstance();
state is GetDevicesLoading || // Handle state priority: Errors first
state is DevicesCategoriesLoading) { if (homeState is ActivationError) {
return const Center(child: CircularProgressIndicator()); return const CreateUnitWidget();
} else {
return HomeCubit.getInstance().spaces?.isEmpty ?? true
? const CreateUnitWidget()
: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
TitleMedium(
text: StringsManager.devices,
style: context.titleMedium.copyWith(
fontSize: 25,
),
),
],
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.1,
child: const SceneView(
pageType: true,
)),
const SizedBox(
height: 20,
),
const RoomsSlider(),
const SizedBox(
height: 10,
),
Expanded(
child: PageView(
controller: HomeCubit.getInstance().devicesPageController,
onPageChanged: (index) {
HomeCubit.getInstance().devicesPageChanged(index);
},
children: [
WizardPage(
groupsList: DevicesCubit.getInstance().allCategories ?? [],
),
if (HomeCubit.getInstance().selectedSpace != null)
...HomeCubit.getInstance().selectedSpace!.subspaces.map(
(room) {
return RoomPage(
room: room,
);
},
)
],
),
),
HomeCubit.getInstance().selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(
vertical: 7,
),
child: SmoothPageIndicator(
controller: HomeCubit.getInstance().devicesPageController,
count: HomeCubit.getInstance().selectedSpace!.subspaces.length + 1,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
),
],
);
} }
// Handle loading states
if (homeState is GetSpacesLoading || homeState is HomeLoading) {
return const Center(child: CircularProgressIndicator());
}
// Handle error states
if (homeState is GetSpacesError) {
return const CreateUnitWidget();
}
// Handle success states
if (homeState is GetSpacesSuccess ||
homeState is RoomUnSelected ||
homeState is RoomSelected ||
homeState is NavChangePage ||
homeState is GetSpaceRoomsSuccess) {
// Show empty state if no spaces
if (homeCubit.spaces.isEmpty) {
return const CreateUnitWidget();
}
return BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, devicesState) {
// Devices loading states
if (devicesState is DevicesLoading ||
devicesState is DevicesCategoriesLoading ||
devicesState is GetDevicesLoading) {
return const Center(child: CircularProgressIndicator());
}
// Devices error state
if (devicesState is GetDevicesError) {
return Center(child: BodyLarge(text: devicesState.errorMsg));
}
// Main content for both GetSpacesSuccess and RoomUnSelected
return _buildMainContent(context, homeCubit);
},
);
}
// Fallback for unknown states
return const Center(child: BodyLarge(text: ''));
}, },
); );
} }
Widget _buildMainContent(BuildContext context, HomeCubit homeCubit) {
final devicesCubit = context.read<DevicesCubit>();
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
TitleMedium(
text: StringsManager.devices,
style: context.titleMedium.copyWith(fontSize: 25),
),
],
),
const SceneView(pageType: true),
const SizedBox(height: 20),
const RoomsSlider(),
const SizedBox(height: 10),
Expanded(
child: PageView(
controller: homeCubit.devicesPageController,
onPageChanged: (index) {
homeCubit.devicesPageChanged(index);
if (index == 0) {
devicesCubit.fetchAllDevices(homeCubit.selectedSpace);
}
},
children: [
AllDevices(
allDevices: devicesCubit.allDevices,
),
WizardPage(
groupsList: devicesCubit.allCategories ?? [],
),
if (homeCubit.selectedSpace != null)
...homeCubit.selectedSpace!.subspaces.map(
(room) => RoomPage(room: room),
),
],
),
),
_buildPageIndicator(homeCubit),
],
);
}
Widget _buildPageIndicator(HomeCubit homeCubit) {
return homeCubit.selectedSpace != null
? Padding(
padding: const EdgeInsets.symmetric(vertical: 7),
child: SmoothPageIndicator(
controller: homeCubit.devicesPageController,
count: homeCubit.selectedSpace!.subspaces.length + 2,
effect: const WormEffect(
paintStyle: PaintingStyle.stroke,
dotHeight: 8,
dotWidth: 8,
),
),
)
: const Center(
child: BodyLarge(text: 'No Home Found'),
);
}
} }

View File

@ -20,8 +20,9 @@ class OneGangScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '') create: (context) =>
..add(const InitialEvent(groupScreen: false)), OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '')
..add(const InitialEvent(groupScreen: false)),
child: BlocBuilder<OneGangBloc, OneGangState>( child: BlocBuilder<OneGangBloc, OneGangState>(
builder: (context, state) { builder: (context, state) {
OneGangModel oneGangModel = OneGangModel( OneGangModel oneGangModel = OneGangModel(
@ -36,13 +37,15 @@ class OneGangScreen extends StatelessWidget {
} }
return state is LoadingInitialState return state is LoadingInitialState
? const Center( ? const Center(
child: child: DefaultContainer(
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), width: 50,
height: 50,
child: CircularProgressIndicator()),
) )
: RefreshIndicator( : RefreshIndicator(
onRefresh: () async { onRefresh: () async {
BlocProvider.of<OneGangBloc>(context) BlocProvider.of<OneGangBloc>(context).add(InitialEvent(
.add(InitialEvent(groupScreen: device != null ? false : true)); groupScreen: device != null ? false : true));
}, },
child: ListView( child: ListView(
children: [ children: [
@ -55,7 +58,8 @@ class OneGangScreen extends StatelessWidget {
const Expanded(child: SizedBox.shrink()), const Expanded(child: SizedBox.shrink()),
Expanded( Expanded(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment:
MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Column( Column(
@ -64,9 +68,10 @@ class OneGangScreen extends StatelessWidget {
threeGangSwitch: device!, threeGangSwitch: device!,
value: oneGangModel.firstSwitch, value: oneGangModel.firstSwitch,
action: () { action: () {
BlocProvider.of<OneGangBloc>(context).add( BlocProvider.of<OneGangBloc>(context)
ChangeFirstSwitchStatusEvent( .add(ChangeFirstSwitchStatusEvent(
value: oneGangModel.firstSwitch)); value: oneGangModel
.firstSwitch));
}, },
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
@ -74,7 +79,8 @@ class OneGangScreen extends StatelessWidget {
width: 70, width: 70,
child: BodySmall( child: BodySmall(
text: " Entrance Light", text: " Entrance Light",
fontColor: ColorsManager.textPrimaryColor, fontColor:
ColorsManager.textPrimaryColor,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@ -94,20 +100,24 @@ class OneGangScreen extends StatelessWidget {
Card( Card(
elevation: 3, elevation: 3,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100), borderRadius:
BorderRadius.circular(100),
), ),
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: pageBuilder: (context,
(context, animation1, animation2) => animation1,
TimerScheduleScreen( animation2) =>
switchCode: 'switch_1', TimerScheduleScreen(
device: device!, switchCode:
deviceCode: 'countdown_1', 'switch_1',
))); device: device!,
deviceCode:
'countdown_1',
)));
}, },
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
@ -117,7 +127,9 @@ class OneGangScreen extends StatelessWidget {
height: 60, height: 60,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey[300], color: Colors.grey[300],
borderRadius: BorderRadius.circular(100), borderRadius:
BorderRadius.circular(
100),
), ),
), ),
Container( Container(
@ -125,12 +137,15 @@ class OneGangScreen extends StatelessWidget {
height: 40, height: 40,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(100), borderRadius:
BorderRadius.circular(
100),
), ),
child: Center( child: Center(
child: Icon( child: Icon(
Icons.access_time, Icons.access_time,
color: ColorsManager.primaryColorWithOpacity, color: ColorsManager
.primaryColorWithOpacity,
size: 25, size: 25,
), ),
), ),

View File

@ -5,6 +5,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.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/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/6_scene_switch/six_scene_screen.dart'; import 'package:syncrow_app/features/devices/view/widgets/6_scene_switch/six_scene_screen.dart';
@ -28,23 +29,31 @@ import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interf
import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_heater/water_heater_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/water_heater/water_heater_page.dart';
import 'package:syncrow_app/features/devices/view/widgets/water_leak/water_leak_screen.dart'; import 'package:syncrow_app/features/devices/view/widgets/water_leak/water_leak_screen.dart';
import 'package:syncrow_app/features/shared_widgets/custom_switch.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
class RoomPageSwitch extends StatelessWidget { class RoomPageSwitch extends StatelessWidget {
const RoomPageSwitch({ const RoomPageSwitch(
super.key, {super.key,
required this.device, required this.device,
}); this.isAllDevices = false,
this.allDevices});
final DeviceModel device; final DeviceModel device;
final List<DeviceModel>? allDevices;
final bool isAllDevices;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
showDeviceInterface(device, context); showDeviceInterface(
device: device,
context: context,
isAllDevices: isAllDevices,
allDevices: allDevices);
}, },
child: DefaultContainer( child: DefaultContainer(
padding: const EdgeInsets.all(15), padding: const EdgeInsets.all(15),
@ -60,22 +69,38 @@ class RoomPageSwitch extends StatelessWidget {
device.icon!, device.icon!,
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
// CustomSwitch( isAllDevices
// device: device, ? CustomSwitch(
// ), device: device,
)
: const SizedBox(),
], ],
), ),
Flexible( Flexible(
child: FittedBox( child: FittedBox(
child: Text( child: Column(
device.name ?? "", crossAxisAlignment: CrossAxisAlignment.start,
overflow: TextOverflow.ellipsis, children: [
maxLines: 2, Text(
style: context.bodyLarge.copyWith( device.name ?? "",
fontWeight: FontWeight.bold, overflow: TextOverflow.ellipsis,
fontSize: 20, maxLines: 2,
color: Colors.grey, style: context.bodyLarge.copyWith(
), fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.grey,
),
),
Text(
device.subspace!.subspaceName ?? '',
overflow: TextOverflow.ellipsis,
style: context.bodySmall.copyWith(
fontWeight: FontWeight.w400,
fontSize: 10,
color: Colors.grey,
),
),
],
), ),
), ),
), ),
@ -89,14 +114,25 @@ class RoomPageSwitch extends StatelessWidget {
/// Shows the device interface based on the product type of the device. /// Shows the device interface based on the product type of the device.
/// ///
/// The [device] parameter represents the device model. /// The [device] parameter represents the device model.
void showDeviceInterface(DeviceModel device, BuildContext context) { Future<void> showDeviceInterface(
{required DeviceModel device,
required BuildContext context,
required isAllDevices,
List<DeviceModel>? allDevices}) async {
print('object-----${device.uuid} ${device.name}');
final devicesCubit = context.read<DevicesCubit>();
switch (device.productType) { switch (device.productType) {
case DeviceType.AC: case DeviceType.AC:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
ACsView(deviceModel: device))); ACsView(deviceModel: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
// navigateToInterface(ACsView(deviceModel: device), context); // navigateToInterface(ACsView(deviceModel: device), context);
break; break;
case DeviceType.WallSensor: case DeviceType.WallSensor:
@ -116,12 +152,15 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
// navigateToInterface(CeilingSensorInterface(ceilingSensor: device), context); // navigateToInterface(CeilingSensorInterface(ceilingSensor: device), context);
break; break;
case DeviceType.Curtain: case DeviceType.Curtain:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => CurtainView( pageBuilder: (context, animation1, animation2) => CurtainView(
curtain: device, curtain: device,
))); )));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
break; break;
case DeviceType.Blind: case DeviceType.Blind:
break; break;
@ -143,30 +182,43 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
case DeviceType.LightBulb: case DeviceType.LightBulb:
navigateToInterface(LightInterface(light: device), context); navigateToInterface(LightInterface(light: device), context);
case DeviceType.OneGang: case DeviceType.OneGang:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
OneGangInterface(gangSwitch: device))); OneGangInterface(gangSwitch: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.TwoGang: case DeviceType.TwoGang:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
TwoGangInterface(gangSwitch: device))); TwoGangInterface(gangSwitch: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.ThreeGang: case DeviceType.ThreeGang:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
ThreeGangInterface(gangSwitch: device))); ThreeGangInterface(gangSwitch: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.WH: case DeviceType.WH:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
WaterHeaterPage(device: device))); WaterHeaterPage(device: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.DS: case DeviceType.DS:
Navigator.push( Navigator.push(
context, context,
@ -182,31 +234,43 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
PowerClampPage(device: device))); PowerClampPage(device: device)));
case DeviceType.OneTouch: case DeviceType.OneTouch:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
OneTouchScreen(device: device))); OneTouchScreen(device: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.TowTouch: case DeviceType.TowTouch:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
TwoTouchInterface(touchSwitch: device))); TwoTouchInterface(touchSwitch: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.ThreeTouch: case DeviceType.ThreeTouch:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
ThreeTouchInterface(touchSwitch: device))); ThreeTouchInterface(touchSwitch: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.GarageDoor: case DeviceType.GarageDoor:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
GarageDoorScreen(device: device))); GarageDoorScreen(device: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.WaterLeak: case DeviceType.WaterLeak:
Navigator.push( Navigator.push(
@ -216,18 +280,24 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
WaterLeakScreen(device: device))); WaterLeakScreen(device: device)));
case DeviceType.SixScene: case DeviceType.SixScene:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
SixSceneScreen(device: device))); SixSceneScreen(device: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.FourScene: case DeviceType.FourScene:
Navigator.push( var value = await Navigator.push(
context, context,
PageRouteBuilder( PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => pageBuilder: (context, animation1, animation2) =>
FourSceneScreen(device: device))); FourSceneScreen(device: device)));
if (value && isAllDevices) {
devicesCubit.fetchAllDevices(HomeCubit.getInstance().selectedSpace);
}
case DeviceType.SOS: case DeviceType.SOS:
Navigator.push( Navigator.push(

View File

@ -23,6 +23,21 @@ class RoomsSlider extends StatelessWidget {
HomeCubit.getInstance().roomSliderPageChanged(index); HomeCubit.getInstance().roomSliderPageChanged(index);
}, },
children: [ children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () {
HomeCubit.getInstance().unselectRoom();
},
child: TitleMedium(
text: 'All Devices',
style: context.titleMedium.copyWith(
fontSize: 25,
color: ColorsManager.textPrimaryColor,
),
),
),
),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell( child: InkWell(
@ -43,7 +58,10 @@ class RoomsSlider extends StatelessWidget {
(room) => InkWell( (room) => InkWell(
onTap: () { onTap: () {
HomeCubit.getInstance().roomSliderPageChanged( HomeCubit.getInstance().roomSliderPageChanged(
HomeCubit.getInstance().selectedSpace!.subspaces.indexOf(room)); HomeCubit.getInstance()
.selectedSpace!
.subspaces
.indexOf(room));
}, },
child: TitleMedium( child: TitleMedium(
text: room.name!, text: room.name!,
@ -51,7 +69,8 @@ class RoomsSlider extends StatelessWidget {
fontSize: 25, fontSize: 25,
color: HomeCubit.getInstance().selectedRoom == room color: HomeCubit.getInstance().selectedRoom == room
? ColorsManager.textPrimaryColor ? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor.withOpacity(.2), : ColorsManager.textPrimaryColor
.withOpacity(.2),
), ),
), ),
), ),

View File

@ -1,14 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart'; import 'package:syncrow_app/features/scene/bloc/scene_bloc/scene_event.dart';
import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
import 'package:syncrow_app/features/scene/model/scenes_model.dart'; import 'package:syncrow_app/features/scene/model/scenes_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
class SceneListview extends StatelessWidget { class SceneListview extends StatelessWidget {
final List<ScenesModel> scenes; final List<ScenesModel> scenes;
@ -31,23 +28,28 @@ class SceneListview extends StatelessWidget {
padding: const EdgeInsets.only(right: 10), padding: const EdgeInsets.only(right: 10),
child: DefaultContainer( child: DefaultContainer(
onTap: () { onTap: () {
Navigator.pushNamed( context
context, .read<SceneBloc>()
Routes.sceneTasksRoute, .add(SceneTrigger(scene.id, scene.name));
arguments: SceneSettingsRouteArguments( // Navigator.pushNamed(
sceneType: CreateSceneEnum.tabToRun.name, // context,
sceneId: scene.id, // Routes.sceneTasksRoute,
sceneName: scene.name, // arguments: SceneSettingsRouteArguments(
), // sceneType: CreateSceneEnum.tabToRun.name,
); // sceneId: scene.id,
context.read<SmartSceneSelectBloc>().add(const SmartSceneClearEvent()); // sceneName: scene.name,
// ),
// );
// context.read<SmartSceneSelectBloc>()
// .add(const SmartSceneClearEvent());
BlocProvider.of<CreateSceneBloc>(context) // BlocProvider.of<CreateSceneBloc>(context).add(
.add(FetchSceneTasksEvent(sceneId: scene.id, isAutomation: false)); // FetchSceneTasksEvent(
// sceneId: scene.id, isAutomation: false));
/// the state to set the scene type must be after the fetch // /// the state to set the scene type must be after the fetch
BlocProvider.of<CreateSceneBloc>(context) // BlocProvider.of<CreateSceneBloc>(context)
.add(const SceneTypeEvent(CreateSceneEnum.tabToRun)); // .add(const SceneTypeEvent(CreateSceneEnum.tabToRun));
}, },
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width * 0.4, width: MediaQuery.of(context).size.width * 0.4,
@ -62,7 +64,8 @@ class SceneListview extends StatelessWidget {
height: 32, height: 32,
width: 32, width: 32,
fit: BoxFit.fill, fit: BoxFit.fill,
errorBuilder: (context, error, stackTrace) => Image.asset( errorBuilder: (context, error, stackTrace) =>
Image.asset(
Assets.assetsIconsLogo, Assets.assetsIconsLogo,
height: 32, height: 32,
width: 32, width: 32,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/members_management_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/members_management_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/smart_linkage_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/smart_linkage_view.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/temporary_password_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/temporary_password_page.dart';
@ -14,6 +15,8 @@ class DoorLockGrid extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final buttons = doorLockButtons(val: uuid);
return GridView.builder( return GridView.builder(
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
@ -23,14 +26,15 @@ class DoorLockGrid extends StatelessWidget {
crossAxisSpacing: 10, crossAxisSpacing: 10,
childAspectRatio: 1.75 / 1, childAspectRatio: 1.75 / 1,
), ),
itemCount: 4, itemCount: buttons.length,
itemBuilder: (context, index) => DefaultContainer( itemBuilder: (context, index) => DefaultContainer(
onTap: () { onTap: () {
//TODO: remove checking after adding the pages //TODO: remove checking after adding the pages
doorLockButtons()[index]['page'] != null doorLockButtons()[index]['page'] != null
? Navigator.of(context).push( ? Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => doorLockButtons(val: uuid)[index]['page'] as Widget, builder: (context) =>
doorLockButtons(val: uuid)[index]['page'] as Widget,
), ),
) )
: null; : null;
@ -75,11 +79,12 @@ List<Map<String, dynamic>> doorLockButtons({val}) => [
'image': Assets.assetsIconsDoorlockAssetsMembersManagement, 'image': Assets.assetsIconsDoorlockAssetsMembersManagement,
'page': const MembersManagementView(), 'page': const MembersManagementView(),
}, },
{ if (HomeCubit.manageDeviceLocation)
'title': 'Temporary Password', {
'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword, 'title': 'Temporary Password',
'page': TemporaryPasswordPage(deviceId: val), 'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword,
}, 'page': TemporaryPasswordPage(deviceId: val),
},
{ {
'title': 'Smart Linkage', 'title': 'Smart Linkage',
'image': Assets.assetsIconsDoorlockAssetsSmartLinkage, 'image': Assets.assetsIconsDoorlockAssetsSmartLinkage,

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart'; import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_screen.dart'; import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_screen.dart';
@ -26,6 +28,7 @@ class TwoTouchInterface extends StatelessWidget {
extendBody: true, extendBody: true,
appBar: touchSwitch != null appBar: touchSwitch != null
? DeviceAppbar( ? DeviceAppbar(
value: true,
deviceName: touchSwitch!.name!, deviceName: touchSwitch!.name!,
deviceUuid: touchSwitch!.uuid!, deviceUuid: touchSwitch!.uuid!,
) )

View File

@ -215,8 +215,7 @@ class ParametersList extends StatelessWidget {
{ {
'icon': Assets.assetsIconsPresenceSensorAssetsEmpty, 'icon': Assets.assetsIconsPresenceSensorAssetsEmpty,
'title': 'Nobody Time', 'title': 'Nobody Time',
'code': null, 'code': 'no_one_time',
//TODO: Implement the nobody time
}, },
{ {
'icon': Assets.assetsIconsPresenceSensorAssetsIndicator, 'icon': Assets.assetsIconsPresenceSensorAssetsIndicator,
@ -231,7 +230,7 @@ class ParametersList extends StatelessWidget {
{ {
'icon': Assets.assetsIconsPresenceSensorAssetsIlluminanceRecord, 'icon': Assets.assetsIconsPresenceSensorAssetsIlluminanceRecord,
'title': 'Illuminance Record', 'title': 'Illuminance Record',
'code': null 'code': 'illuminance_value'
}, },
]; ];
} }
@ -240,6 +239,7 @@ Widget listItem(Map<String, Object?> wallSensorButton, BuildContext context, Dev
WallSensorModel wallSensorStatus) { WallSensorModel wallSensorStatus) {
String? unit; String? unit;
dynamic value; dynamic value;
int noBodyTimeValue;
if (wallSensorButton['code'] != null) { if (wallSensorButton['code'] != null) {
// if (wallSensor.status.any((element) => element.code == wallSensorButton['code'] as String)) { // if (wallSensor.status.any((element) => element.code == wallSensorButton['code'] as String)) {
// unit = unitsMap[wallSensorButton['code'] as String]; // unit = unitsMap[wallSensorButton['code'] as String];
@ -256,12 +256,15 @@ Widget listItem(Map<String, Object?> wallSensorButton, BuildContext context, Dev
} else if (wallSensorButton['code'] == 'illuminance_value') { } else if (wallSensorButton['code'] == 'illuminance_value') {
unit = unitsMap[wallSensorButton['code'] as String]; unit = unitsMap[wallSensorButton['code'] as String];
value = wallSensorStatus.illuminance; value = wallSensorStatus.illuminance;
} else if (wallSensorButton['code'] == 'no_one_time') {
unit = unitsMap[wallSensorButton['code'] as String];
value = wallSensorStatus.noOneTime;
} }
} }
return DefaultContainer( return DefaultContainer(
margin: const EdgeInsets.only(bottom: 5), margin: const EdgeInsets.only(bottom: 5),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
onTap: () { onTap: () async {
if (wallSensorButton['page'] != null) { if (wallSensorButton['page'] != null) {
Navigator.push( Navigator.push(
context, context,
@ -270,6 +273,42 @@ Widget listItem(Map<String, Object?> wallSensorButton, BuildContext context, Dev
), ),
); );
} }
if (wallSensorButton['title'] == 'Presence Record') {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PresenceRecords(
deviceId: wallSensor.uuid!,
code: 'presence_state',
title: 'Presence Record',
)),
);
}
if (wallSensorButton['title'] == 'Illuminance Record') {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PresenceRecords(
deviceId: wallSensor.uuid!,
code: 'illuminance_value',
title: 'Illuminance Record',
)),
);
}
if (wallSensorButton['title'] == 'Nobody Time') {
int noBodyTimeValue = value as int;
String controlCode = 'no_one_time';
final result = await showDialog(
context: context,
builder: (context) => ParameterControlDialog(
title: 'Nobody Time', sensor: wallSensor, value: noBodyTimeValue, min: 0, max: 10000),
);
if (result != null) {
BlocProvider.of<WallSensorBloc>(context)
.add(ChangeValueEvent(value: result, code: controlCode));
}
}
}, },
child: Row( child: Row(
children: [ children: [

View File

@ -0,0 +1,120 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_event.dart';
import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_state.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class PresenceRecords extends StatelessWidget {
final String deviceId;
final String code;
final String title;
const PresenceRecords(
{super.key, required this.deviceId, required this.code, required this.title});
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: title,
child: BlocProvider(
create: (context) => WallSensorBloc(deviceId: deviceId)
..add(GetDeviceReportsEvent(deviceUuid: deviceId, code: code)),
child: BlocBuilder<WallSensorBloc, WallSensorState>(builder: (context, state) {
final Map<String, List<DeviceEvent>> groupedRecords = {};
if (state is LoadingInitialState) {
return const Center(
child: DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
);
} else if (state is DeviceReportsState) {
for (var record in state.deviceReport.data ?? []) {
final DateTime eventDateTime = DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
final String formattedDate = DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
// Group by formatted date
if (groupedRecords.containsKey(formattedDate)) {
groupedRecords[formattedDate]!.add(record);
} else {
groupedRecords[formattedDate] = [record];
}
}
}
return groupedRecords.isEmpty
? const Center(
child: Text('No records found'),
)
: ListView.builder(
itemCount: groupedRecords.length,
itemBuilder: (context, index) {
final String date = groupedRecords.keys.elementAt(index);
final List<DeviceEvent> recordsForDate = groupedRecords[date]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 5, top: 10),
child: Text(
date,
style: const TextStyle(
color: ColorsManager.grayColor,
fontSize: 13,
fontWeight: FontWeight.w700,
),
),
),
DefaultContainer(
child: Column(
children: [
...recordsForDate.asMap().entries.map((entry) {
final int idx = entry.key;
final DeviceEvent record = entry.value;
final DateTime eventDateTime =
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
final String formattedTime =
DateFormat('HH:mm:ss').format(eventDateTime);
return Column(
children: [
Container(
child: ListTile(
leading: Icon(
record.value == 'true'
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color: record.value == 'true' ? Colors.blue : Colors.grey,
),
title: Text(
record.value == 'true' ? "Opened" : "Closed",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
subtitle: Text('$formattedTime'),
),
),
if (idx != recordsForDate.length - 1)
const Divider(
color: ColorsManager.graysColor,
),
],
);
}).toList(),
],
),
),
],
);
},
);
}),
),
);
}
}

View File

@ -1,3 +1,5 @@
import 'dart:ffi';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -9,6 +11,8 @@ import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_e
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart'; import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart'; import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_records_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/persence_records.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
@ -41,7 +45,8 @@ class WallMountedInterface extends StatelessWidget {
motionlessSensitivity: 0, motionlessSensitivity: 0,
currentDistance: 0, currentDistance: 0,
illuminance: 0, illuminance: 0,
indicator: false); indicator: false,
noOneTime: 0);
if (state is UpdateState) { if (state is UpdateState) {
wallSensorModel = state.wallSensorModel; wallSensorModel = state.wallSensorModel;

View File

@ -1,10 +1,12 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart'; import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart'; import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart'; import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
import 'package:syncrow_app/services/api/home_creation_api.dart'; import 'package:syncrow_app/services/api/home_creation_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> { class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
@ -239,8 +241,13 @@ Future<String> _createNewRoom(
required String communityId}) async { required String communityId}) async {
try { try {
Map<String, String> body = {'subspaceName': roomName}; Map<String, String> body = {'subspaceName': roomName};
Project? project = HomeCubit.getInstance().project;
final response = await HomeCreation.createRoom( final response = await HomeCreation.createRoom(
communityId: communityId, spaceId: unitId, body: body); communityId: communityId,
spaceId: unitId,
body: body,
projectId: project?.uuid ?? TempConst.projectIdDev);
// if (response['data']['uuid'] != '') { // if (response['data']['uuid'] != '') {
// final result = await _assignToRoom(roomId: response['data']['uuid'], userId: userId); // final result = await _assignToRoom(roomId: response['data']['uuid'], userId: userId);

View File

@ -1,5 +1,6 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/auth/model/project_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_event.dart'; import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_event.dart';
import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_state.dart'; import 'package:syncrow_app/features/menu/bloc/manage_unit_bloc/manage_unit_state.dart';
@ -7,6 +8,7 @@ import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_creation_api.dart'; import 'package:syncrow_app/services/api/home_creation_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart'; import 'package:syncrow_app/services/api/home_management_api.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/constants/temp_const.dart';
class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> { class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
List<DeviceModel> allDevices = []; List<DeviceModel> allDevices = [];
@ -24,8 +26,12 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
FetchRoomsEvent event, Emitter<ManageUnitState> emit) async { FetchRoomsEvent event, Emitter<ManageUnitState> emit) async {
try { try {
emit(LoadingState()); emit(LoadingState());
Project? project = HomeCubit.getInstance().project;
final roomsList = await SpacesAPI.getSubSpaceBySpaceId( final roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id); event.unit.community.uuid,
event.unit.id,
project?.uuid ?? TempConst.projectIdDev);
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList)); emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
} catch (e) { } catch (e) {
emit(const ErrorState(message: 'Something went wrong')); emit(const ErrorState(message: 'Something went wrong'));
@ -37,12 +43,16 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
FetchDevicesByRoomIdEvent event, Emitter<ManageUnitState> emit) async { FetchDevicesByRoomIdEvent event, Emitter<ManageUnitState> emit) async {
try { try {
Map<String, bool> roomDevicesId = {}; Map<String, bool> roomDevicesId = {};
Project? project = HomeCubit.getInstance().project;
emit(LoadingState()); emit(LoadingState());
final devicesList = await DevicesAPI.getDevicesByRoomId( final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid, communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id, spaceUuid: event.unit.id,
roomId: event.roomId); roomId: event.roomId,
allDevices = await HomeManagementAPI.fetchDevicesByUserId(); projectId: project?.uuid ?? TempConst.projectIdDev);
allDevices = await HomeManagementAPI.fetchDevices(
project?.uuid ?? TempConst.projectIdDev);
List<String> allDevicesIds = []; List<String> allDevicesIds = [];
@ -72,14 +82,21 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
AssignRoomEvent event, Emitter<ManageUnitState> emit) async { AssignRoomEvent event, Emitter<ManageUnitState> emit) async {
try { try {
Map<String, bool> roomDevicesId = {}; Map<String, bool> roomDevicesId = {};
Project? project = HomeCubit.getInstance().project;
emit(LoadingState()); emit(LoadingState());
await HomeManagementAPI.assignDeviceToRoom( await HomeManagementAPI.assignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, event.deviceId); event.unit.community.uuid,
event.unit.id,
event.roomId,
event.deviceId,
project?.uuid ?? TempConst.projectIdDev);
final devicesList = await DevicesAPI.getDevicesByRoomId( final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid, communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id, spaceUuid: event.unit.id,
roomId: event.roomId); roomId: event.roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
List<String> allDevicesIds = []; List<String> allDevicesIds = [];
@ -105,19 +122,25 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
} }
} }
void _unassignDevice( void _unassignDevice(
UnassignRoomEvent event, Emitter<ManageUnitState> emit) async { UnassignRoomEvent event, Emitter<ManageUnitState> emit) async {
try { try {
Map<String, bool> roomDevicesId = {}; Map<String, bool> roomDevicesId = {};
Project? project = HomeCubit.getInstance().project;
emit(LoadingState()); emit(LoadingState());
await HomeManagementAPI.unAssignDeviceToRoom( await HomeManagementAPI.unAssignDeviceToRoom(
event.unit.community.uuid, event.unit.id, event.roomId, event.deviceId); event.unit.community.uuid,
event.unit.id,
event.roomId,
event.deviceId,
project?.uuid ?? TempConst.projectIdDev);
final devicesList = await DevicesAPI.getDevicesByRoomId( final devicesList = await DevicesAPI.getDevicesByRoomId(
communityUuid: event.unit.community.uuid, communityUuid: event.unit.community.uuid,
spaceUuid: event.unit.id, spaceUuid: event.unit.id,
roomId: event.roomId); roomId: event.roomId,
projectId: project?.uuid ?? TempConst.projectIdDev);
List<String> allDevicesIds = []; List<String> allDevicesIds = [];
@ -143,18 +166,22 @@ class ManageUnitBloc extends Bloc<ManageUnitEvent, ManageUnitState> {
} }
} }
_addNewRoom(AddNewRoom event, Emitter<ManageUnitState> emit) async { _addNewRoom(AddNewRoom event, Emitter<ManageUnitState> emit) async {
Map<String, String> body = {'subspaceName': event.roomName}; Map<String, String> body = {'subspaceName': event.roomName};
try { try {
emit(LoadingState()); emit(LoadingState());
Project? project = HomeCubit.getInstance().project;
final response = await HomeCreation.createRoom( final response = await HomeCreation.createRoom(
communityId: event.unit.community.uuid, communityId: event.unit.community.uuid,
spaceId: event.unit.id, spaceId: event.unit.id,
body: body); body: body,
projectId: project?.uuid ?? TempConst.projectIdDev);
if (response['data']['uuid'] != '') { if (response['data']['uuid'] != '') {
final roomsList = await SpacesAPI.getSubSpaceBySpaceId( final roomsList = await SpacesAPI.getSubSpaceBySpaceId(
event.unit.community.uuid, event.unit.id); event.unit.community.uuid,
event.unit.id,
project?.uuid ?? TempConst.projectIdDev);
allDevices = await HomeManagementAPI.fetchDevicesByUserId(); allDevices = await HomeManagementAPI.fetchDevicesByUserId();
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList)); emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
await HomeCubit.getInstance().fetchUnitsByUserId(); await HomeCubit.getInstance().fetchUnitsByUserId();

View File

@ -1,12 +1,184 @@
import 'dart:ui';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/menu/bloc/privacy_policy.dart';
import 'package:syncrow_app/features/menu/bloc/user_agreement.dart';
import 'package:syncrow_app/features/menu/view/widgets/join_home/join_home_view.dart';
import 'package:syncrow_app/features/menu/view/widgets/manage_home/manage_home_view.dart';
import 'package:syncrow_app/features/menu/view/widgets/securty/view/securty_view.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/services/api/profile_api.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
part 'menu_state.dart'; part 'menu_state.dart';
class MenuCubit extends Cubit<MenuState> { class MenuCubit extends Cubit<MenuState> {
MenuCubit() : super(MenuInitial()); MenuCubit() : super(MenuInitial());
static MenuCubit of(context) => BlocProvider.of<MenuCubit>(context); static MenuCubit of(context) => BlocProvider.of<MenuCubit>(context);
String name = ''; String name = '';
String userAgreementHtml = "";
String privacyPolicyHtml = "";
Future<void> fetchAgreement() async {
try {
emit(MenuLoading());
final response = await ProfileApi().fetchUserAgreement();
userAgreementHtml = response;
emit(MenuLoaded(userAgreementHtml));
} catch (error) {
emit(MenuError(error.toString()));
}
}
Future<void> fetchPrivacyPolicy() async {
try {
emit(MenuLoading());
final response = await ProfileApi().fetchPrivacyPolicy();
privacyPolicyHtml = response;
emit(MenuLoaded(privacyPolicyHtml));
} catch (error) {
emit(MenuError(error.toString()));
}
}
List<Map<String, Object>> menuSections = [
//Home Management
{
'title': 'Home Management',
'color': ColorsManager.primaryColor,
'buttons': [
// {
// 'title': 'Create a Unit',
// 'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsCreateHome,
// 'page': const CreateUnitView()
// },
{
'title': 'Join a Unit',
'Icon': Assets.assetsIconsMenuIconsHomeManagementIconsJoinAHome,
'page': const JoinHomeView()
},
if (HomeCubit.manageSupSpace)
{
'title': 'Manage Your Units',
'Icon':
Assets.assetsIconsMenuIconsHomeManagementIconsManageYourHome,
'page': const ManageHomeView()
},
],
},
//General Settings
// {
// 'title': 'General Settings',
// 'color': const Color(0xFF023DFE),
// 'buttons': [
// {
// 'title': 'Voice Assistant',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsVoiceAssistant,
// 'page': null
// },
// {
// 'title': 'Temperature unit',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsTemperatureUnit,
// 'page': null
// },
// {
// 'title': 'Touch tone on panel',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsTouchTone,
// 'page': null
// },
// {
// 'title': 'Language',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsLanguage,
// 'page': null
// },
// {
// 'title': 'Network Diagnosis',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsNetworkDiagnosis,
// 'page': null
// },
// {
// 'title': 'Clear Cache',
// 'Icon': Assets.assetsIconsMenuIconsGeneralSettingsIconsClearCach,
// 'page': null
// },
// ],
// },
// //Messages Center
// {
// 'title': 'Messages Center',
// 'color': const Color(0xFF0088FF),
// 'buttons': [
// {
// 'title': 'Alerts',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsAlerts,
// 'page': null
// },
// {
// 'title': 'Messages',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsMessages,
// 'page': null
// },
// {
// 'title': 'FAQs',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsFAQs,
// 'page': null
// },
// {
// 'title': 'Help & Feedback',
// 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsHelpAndFeedback,
// 'page': null
// },
// ],
// },
//Security And Privacy
{
'title': 'Security And Privacy',
'color': const Color(0xFF8AB9FF),
'buttons': [
{
'title': 'Security',
'Icon': Assets.assetsIconsMenuIconsSecurityAndPrivacyIconsSecurty,
'page': const SecurtyView()
},
// {
// 'title': 'Privacy',
// 'Icon': Assets.assetsIconsMenuIconsSecurityAndPrivacyIconsPrivacy,
// 'page': const PrivacyView()
// },
],
},
//Legal Information
{
'title': 'Legal Information',
'color': const Color(0xFF001B72),
'buttons': [
// {
// 'title': 'About',
// 'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsAbout,
// 'page': null
// },
{
'title': 'Privacy Policy',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsPrivacyPolicy,
'page': const PrivacyPolicy()
},
{
'title': 'User Agreement',
'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsUserAgreement,
'page': const UserAgreement()
},
],
},
];
Future<void> fetchMenuSections() async {
emit(MenuLoading());
try {
emit(MenuItemsLoaded(menuSections));
} catch (e) {
emit(MenuError(e.toString()));
}
}
} }

View File

@ -3,3 +3,27 @@ part of 'menu_cubit.dart';
abstract class MenuState {} abstract class MenuState {}
class MenuInitial extends MenuState {} class MenuInitial extends MenuState {}
class MenuLoading extends MenuState {}
class MenuLoaded extends MenuState {
final String userAgreementHtml;
MenuLoaded(this.userAgreementHtml);
}
class MenuItemsLoaded extends MenuState {
final List<Map<String, Object>> menuSections;
MenuItemsLoaded(this.menuSections);
}
class MenuError extends MenuState {
final String message;
MenuError(this.message);
}
class MenuNameUpdated extends MenuState {
final String name;
MenuNameUpdated(this.name);
}

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:url_launcher/url_launcher.dart';
class PrivacyPolicy extends StatefulWidget {
const PrivacyPolicy({super.key});
@override
_PrivacyPolicyState createState() => _PrivacyPolicyState();
}
class _PrivacyPolicyState extends State<PrivacyPolicy> {
@override
void initState() {
super.initState();
MenuCubit.of(context).fetchPrivacyPolicy();
}
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Privacy Policy',
child: BlocBuilder<MenuCubit, MenuState>(
builder: (context, state) {
if (state is MenuLoading) {
return const Center(child: CircularProgressIndicator());
} else if (state is MenuLoaded) {
return ListView(
children: [
Html(
data: state.userAgreementHtml.isNotEmpty
? state.userAgreementHtml
: '',
onLinkTap: (url, attributes, element) async {
final uri = Uri.parse(url!);
await launchUrl(uri, mode: LaunchMode.externalApplication);
},
),
],
);
} else if (state is MenuError) {
return Center(
child: Text(
'Error: ${state.message}',
style: const TextStyle(color: Colors.red),
),
);
}
return const Center(child: Text('Loading User Agreement...'));
},
),
);
}
}

View File

@ -23,8 +23,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
String timeZoneSelected = ''; String timeZoneSelected = '';
String regionSelected = ''; String regionSelected = '';
final TextEditingController searchController = TextEditingController(); final TextEditingController searchController = TextEditingController();
final TextEditingController nameController = final TextEditingController nameController = TextEditingController(
TextEditingController(text: '${HomeCubit.user!.firstName} ${HomeCubit.user!.lastName}'); text: '${HomeCubit.user!.firstName} ${HomeCubit.user!.lastName}');
List<RegionModel> allRegions = []; List<RegionModel> allRegions = [];
List<TimeZone> allTimeZone = []; List<TimeZone> allTimeZone = [];
@ -77,10 +77,13 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
emit(NameEditingState(editName: editName)); emit(NameEditingState(editName: editName));
} }
void _fetchUserInfo(InitialProfileEvent event, Emitter<ProfileState> emit) async { void _fetchUserInfo(
InitialProfileEvent event, Emitter<ProfileState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
HomeCubit.user = await ProfileApi().fetchUserInfo(HomeCubit.user!.uuid); HomeCubit.user = await ProfileApi().fetchUserInfo(HomeCubit.user!.uuid);
HomeCubit.getInstance().project = HomeCubit.user?.project;
emit(SaveState()); emit(SaveState());
} catch (e) { } catch (e) {
emit(FailedState(errorMessage: e.toString())); emit(FailedState(errorMessage: e.toString()));
@ -88,7 +91,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
} }
Future _fetchTimeZone(TimeZoneInitialEvent event, Emitter<ProfileState> emit) async { Future _fetchTimeZone(
TimeZoneInitialEvent event, Emitter<ProfileState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
try { try {
allTimeZone = await ProfileApi.fetchTimeZone(); allTimeZone = await ProfileApi.fetchTimeZone();
@ -100,7 +104,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
} }
Future selectTimeZone(SelectTimeZoneEvent event, Emitter<ProfileState> emit) async { Future selectTimeZone(
SelectTimeZoneEvent event, Emitter<ProfileState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
timeZoneSelected = event.val; timeZoneSelected = event.val;
@ -112,7 +117,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
} }
Future selectRegion(SelectRegionEvent event, Emitter<ProfileState> emit) async { Future selectRegion(
SelectRegionEvent event, Emitter<ProfileState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
await ProfileApi.saveRegion(regionUuid: event.val); await ProfileApi.saveRegion(regionUuid: event.val);
@ -124,7 +130,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
} }
Future<void> searchRegion(SearchRegionEvent event, Emitter<ProfileState> emit) async { Future<void> searchRegion(
SearchRegionEvent event, Emitter<ProfileState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
final query = event.query.toLowerCase(); final query = event.query.toLowerCase();
if (allRegions.isEmpty) { if (allRegions.isEmpty) {
@ -140,7 +147,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
} }
Future<void> searchTimeZone(SearchTimeZoneEvent event, Emitter<ProfileState> emit) async { Future<void> searchTimeZone(
SearchTimeZoneEvent event, Emitter<ProfileState> emit) async {
emit(LoadingInitialState()); emit(LoadingInitialState());
final query = event.query.toLowerCase(); final query = event.query.toLowerCase();
if (allTimeZone.isEmpty) { if (allTimeZone.isEmpty) {
@ -156,7 +164,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
} }
void _fetchRegion(RegionInitialEvent event, Emitter<ProfileState> emit) async { void _fetchRegion(
RegionInitialEvent event, Emitter<ProfileState> emit) async {
try { try {
emit(LoadingInitialState()); emit(LoadingInitialState());
allRegions = await ProfileApi.fetchRegion(); allRegions = await ProfileApi.fetchRegion();
@ -166,7 +175,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
} }
Future<void> _selectImage(SelectImageEvent event, Emitter<ProfileState> emit) async { Future<void> _selectImage(
SelectImageEvent event, Emitter<ProfileState> emit) async {
try { try {
if (await _requestPermission()) { if (await _requestPermission()) {
emit(ChangeImageState()); emit(ChangeImageState());
@ -283,7 +293,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
} }
return false; return false;
} else { } else {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
bool firstClick = sharedPreferences.getBool('firstPermission') ?? true; bool firstClick = sharedPreferences.getBool('firstPermission') ?? true;
await sharedPreferences.setBool('firstPermission', false); await sharedPreferences.setBool('firstPermission', false);
if (firstClick == false) { if (firstClick == false) {

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:url_launcher/url_launcher.dart';
class UserAgreement extends StatefulWidget {
const UserAgreement({super.key});
@override
_UserAgreementState createState() => _UserAgreementState();
}
class _UserAgreementState extends State<UserAgreement> {
@override
void initState() {
super.initState();
MenuCubit.of(context).fetchAgreement();
}
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'User Agreement',
child: BlocBuilder<MenuCubit, MenuState>(
builder: (context, state) {
if (state is MenuLoading) {
return const Center(child: CircularProgressIndicator());
} else if (state is MenuLoaded) {
return ListView(
children: [
Html(
data: state.userAgreementHtml.isNotEmpty
? state.userAgreementHtml
: '',
onLinkTap: (url, attributes, element) async {
final uri = Uri.parse(url!);
await launchUrl(uri, mode: LaunchMode.externalApplication);
},
),
],
);
} else if (state is MenuError) {
return Center(
child: Text(
'Error: ${state.message}',
style: const TextStyle(color: Colors.red),
),
);
}
return const Center(child: Text('Loading User Agreement...'));
},
),
);
}
}

View File

@ -1,69 +1,62 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart'; import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart';
import 'package:syncrow_app/features/menu/view/widgets/menu_list.dart'; import 'package:syncrow_app/features/menu/view/widgets/menu_list.dart';
import 'package:syncrow_app/features/menu/view/widgets/profile/profile_tab.dart'; import 'package:syncrow_app/features/menu/view/widgets/profile/profile_tab.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class MenuView extends StatelessWidget { class MenuView extends StatelessWidget {
const MenuView({super.key}); const MenuView({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (BuildContext context) => MenuCubit(), create: (BuildContext context) => MenuCubit()..fetchMenuSections(),
child: BlocBuilder<MenuCubit, MenuState>( child: BlocBuilder<MenuCubit, MenuState>(
builder: (context, state) { builder: (context, menuState) {
return BlocBuilder<AuthCubit, AuthState>( if (menuState is MenuLoading) {
builder: (context, state) { return const Center(child: CircularProgressIndicator());
return SingleChildScrollView( } else if (menuState is MenuError) {
physics: const BouncingScrollPhysics(), return Center(child: Text(menuState.message));
child: Column( } else if (menuState is MenuItemsLoaded) {
children: [ final sections = menuState.menuSections;
const ProfileTab(), return SingleChildScrollView(
for (var section in menuSections) physics: const BouncingScrollPhysics(),
MenuList( child: Column(
section: section, children: [
), const ProfileTab(),
const SizedBox( for (var section in sections) MenuList(section: section),
height: 15, const SizedBox(height: 15),
), InkWell(
BodyMedium(text: dotenv.env['ENV_NAME'] ?? ''), onTap: () {
const SizedBox( AuthCubit.get(context).logout();
height: 15, },
), child: Row(
InkWell( children: [
onTap: () { Expanded(
AuthCubit.get(context).logout(); child: DefaultContainer(
}, child: Center(
child: Row( child: BodyLarge(
children: [ text: 'Logout',
Expanded( style: context.bodyLarge.copyWith(
child: DefaultContainer( color: Colors.red,
child: Center(
child: BodyLarge(
text: 'Logout',
style: context.bodyLarge.copyWith(
color: Colors.red,
),
), ),
), ),
), ),
), ),
], ),
), ],
) ),
], ),
), ],
); ),
}, );
); }
// Fallback in case no states match
return const SizedBox.shrink();
}, },
), ),
); );

View File

@ -3,10 +3,12 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/default_scaffold.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/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class JoinHomeView extends StatelessWidget { class JoinHomeView extends StatelessWidget {
const JoinHomeView({super.key}); const JoinHomeView({super.key});
@ -57,14 +59,93 @@ class JoinHomeView extends StatelessWidget {
'Please enter the invitation code'); 'Please enter the invitation code');
return; return;
} }
if (await HomeCubit.getInstance().activationCode(textEditingController.text)) { if (await HomeCubit.getInstance()
.activationCode(textEditingController.text)) {
await HomeCubit.getInstance().fetchUnitsByUserId(); await HomeCubit.getInstance().fetchUnitsByUserId();
CustomSnackBar.displaySnackBar('Done successfully'); CustomSnackBar.displaySnackBar('Done successfully');
Navigator.of(context).pop(); Navigator.of(context).pop();
} else { } else {
CustomSnackBar.displaySnackBar('Wrong code!'); // CustomSnackBar.displaySnackBar('Wrong code!');
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: SizedBox(
height: MediaQuery.of(context).size.height * 0.2,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
const BodyLarge(
text: "Warning",
fontWeight: FontWeight.w700,
fontColor: ColorsManager.red,
fontSize: 16,
),
const Padding(
padding:
EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
Padding(
padding: const EdgeInsets.only(
left: 15,
right: 20,
top: 15,
bottom: 20),
child: Column(
children: [
Center(
child: Text(
HomeCubit.getInstance().errorMsg,
textAlign: TextAlign.center,
)),
],
),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: InkWell(
onTap: () {
Navigator.of(context).pop();
},
child: Padding(
padding: const EdgeInsets.only(
top: 5, bottom: 5),
child: Center(
child: Text(
'Ok',
style: TextStyle(
color: ColorsManager
.switchButton
.withOpacity(0.6),
fontSize: 14,
fontWeight:
FontWeight.w400),
),
),
)),
),
)
],
),
),
);
},
);
} }
}, },
icon: const Icon( icon: const Icon(

Some files were not shown because too many files have changed in this diff Show More