mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-17 02:25:31 +00:00
Compare commits
55 Commits
bugifx/tag
...
connect_re
Author | SHA1 | Date | |
---|---|---|---|
dcfbe5282e | |||
6f2e2e2d4a | |||
fe52726f6e | |||
ba44d1d359 | |||
a623f1c723 | |||
c5f5992c18 | |||
98ad7090d8 | |||
ea08024b82 | |||
f6d66185b3 | |||
ead5297ba1 | |||
9a6bf5cbaf | |||
51fbe64209 | |||
49fa80e7d8 | |||
1aa15e5dd6 | |||
962f2d6861 | |||
bd6219f915 | |||
132cafcaa2 | |||
8862ad95f3 | |||
af4c0f84cb | |||
c2b77ad1fc | |||
95cee89b4c | |||
d5fcbe2601 | |||
1fa33a271f | |||
09e2564183 | |||
5dee6c2842 | |||
a43ff3c07d | |||
572520eed5 | |||
a18e8443d0 | |||
506531e16a | |||
ab3edbaf57 | |||
5ab9664318 | |||
d3bf4de0ca | |||
5ae07688cb | |||
e6fa9c2391 | |||
b070884bd9 | |||
7d05a33c52 | |||
6e546a4831 | |||
b098202fd8 | |||
43c17d1c18 | |||
e70b9ea9e2 | |||
9e0184f19d | |||
ea5b6597f5 | |||
2221d9ae7b | |||
921d352207 | |||
c5871be990 | |||
2fb6f30ccb | |||
508d8bbaa8 | |||
97bdb1bbb7 | |||
7ce0a27af0 | |||
bc4af6a237 | |||
513175ed1e | |||
5060d2a66d | |||
540f569b1f | |||
a98f7e77a3 | |||
0341844ea9 |
@ -1,5 +1,9 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
// START: FlutterFire Configuration
|
||||
id 'com.google.gms.google-services'
|
||||
id 'com.google.firebase.crashlytics'
|
||||
// END: FlutterFire Configuration
|
||||
id "kotlin-android"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
68
android/app/google-services.json
Normal file
68
android/app/google-services.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "427332280600",
|
||||
"firebase_url": "https://test2-8a3d2-default-rtdb.firebaseio.com",
|
||||
"project_id": "test2-8a3d2",
|
||||
"storage_bucket": "test2-8a3d2.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
|
||||
"android_client_info": {
|
||||
"package_name": "com.example.syncrow.app"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:427332280600:android:bb6047adeeb80fb00c7e6d",
|
||||
"android_client_info": {
|
||||
"package_name": "com.example.syncrow_application"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:427332280600:android:2bc36fbe82994a3e0c7e6d",
|
||||
"android_client_info": {
|
||||
"package_name": "com.example.syncrow_web"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
@ -20,6 +20,10 @@ pluginManagement {
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "7.3.0" apply false
|
||||
// START: FlutterFire Configuration
|
||||
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||
id "com.google.firebase.crashlytics" version "2.8.1" apply false
|
||||
// END: FlutterFire Configuration
|
||||
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
||||
}
|
||||
|
||||
|
1
firebase.json
Normal file
1
firebase.json
Normal file
@ -0,0 +1 @@
|
||||
{"flutter":{"platforms":{"android":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:android:2bc36fbe82994a3e0c7e6d","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"macos":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:14346b200780dc760c7e6d","uploadDebugSymbols":true,"fileOutput":"macos/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"test2-8a3d2","configurations":{"android":"1:427332280600:android:2bc36fbe82994a3e0c7e6d","ios":"1:427332280600:ios:14346b200780dc760c7e6d","macos":"1:427332280600:ios:14346b200780dc760c7e6d","web":"1:427332280600:web:ad50516a87a35a1a0c7e6d","windows":"1:427332280600:web:f7a25537ccd5a7bd0c7e6d"}}}}}}
|
@ -15,6 +15,7 @@
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
E44A9405B1EB1B638DD05A58 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ABF0EC746A2D686A0ED574F /* Pods_RunnerTests.framework */; };
|
||||
F2A3345EC3021060731668D3 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B14AB50E8716720E10D074BD /* GoogleService-Info.plist */; };
|
||||
FF49F60EC38658783D8D66DA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AFAE479A87ECDEBD5D6EB30 /* Pods_Runner.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -64,6 +65,7 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B14AB50E8716720E10D074BD /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
D3AD250AADBF93406007C9EB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -138,6 +140,7 @@
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
1454C118FFCECEEDF59152D2 /* Pods */,
|
||||
20A3C64D2B1CFED5A81C3251 /* Frameworks */,
|
||||
B14AB50E8716720E10D074BD /* GoogleService-Info.plist */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@ -199,6 +202,7 @@
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
33590C9CD073D3D5EBA02CDE /* [CP] Embed Pods Frameworks */,
|
||||
7A77858F6F15CB76D2D3A872 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -264,6 +268,7 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
F2A3345EC3021060731668D3 /* GoogleService-Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -303,6 +308,24 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
7A77858F6F15CB76D2D3A872 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\"";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\n#!/bin/bash\nPATH=\"${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\"\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --platform=ios --apple-project-path=\"${SRCROOT}\" --env-platform-name=\"${PLATFORM_NAME}\" --env-configuration=\"${CONFIGURATION}\" --env-project-dir=\"${PROJECT_DIR}\" --env-built-products-dir=\"${BUILT_PRODUCTS_DIR}\" --env-dwarf-dsym-folder-path=\"${DWARF_DSYM_FOLDER_PATH}\" --env-dwarf-dsym-file-name=\"${DWARF_DSYM_FILE_NAME}\" --env-infoplist-path=\"${INFOPLIST_PATH}\" --default-config=default\n";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
|
32
ios/Runner/GoogleService-Info.plist
Normal file
32
ios/Runner/GoogleService-Info.plist
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>427332280600</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>com.example.syncrowWeb</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>test2-8a3d2</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>test2-8a3d2.firebasestorage.app</string>
|
||||
<key>IS_ADS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_ANALYTICS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_APPINVITE_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_GCM_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_SIGNIN_ENABLED</key>
|
||||
<true></true>
|
||||
<key>GOOGLE_APP_ID</key>
|
||||
<string>1:427332280600:ios:14346b200780dc760c7e6d</string>
|
||||
<key>DATABASE_URL</key>
|
||||
<string>https://test2-8a3d2-default-rtdb.firebaseio.com</string>
|
||||
</dict>
|
||||
</plist>
|
@ -46,14 +46,13 @@ class CustomSearchBar extends StatelessWidget {
|
||||
filled: true,
|
||||
fillColor: ColorsManager.textFieldGreyColor,
|
||||
hintText: hintText,
|
||||
hintStyle: TextStyle(
|
||||
color: Color(0xB2999999),
|
||||
fontSize: 12,
|
||||
fontFamily: 'Aftika',
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 0,
|
||||
letterSpacing: -0.24,
|
||||
),
|
||||
hintStyle: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 0,
|
||||
letterSpacing: -0.24,
|
||||
),
|
||||
suffixIcon: Padding(
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: SvgPicture.asset(
|
25
lib/common/widgets/spaces_side_tree.dart
Normal file
25
lib/common/widgets/spaces_side_tree.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
|
||||
class SpacesSideTree extends StatefulWidget {
|
||||
final List<CommunityModel> communities;
|
||||
final String? selectedSpaceUuid;
|
||||
const SpacesSideTree({
|
||||
super.key,
|
||||
required this.communities,
|
||||
this.selectedSpaceUuid,
|
||||
});
|
||||
|
||||
@override
|
||||
State<SpacesSideTree> createState() => _SpacesSideTreeState();
|
||||
}
|
||||
|
||||
class _SpacesSideTreeState extends State<SpacesSideTree> {
|
||||
String _searchQuery = '';
|
||||
String? _selectedSpaceUuid;
|
||||
String? _selectedId;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
}
|
||||
}
|
93
lib/firebase_options_dev.dart
Normal file
93
lib/firebase_options_dev.dart
Normal file
@ -0,0 +1,93 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart'
|
||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptionsDev {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
return web;
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
return android;
|
||||
case TargetPlatform.iOS:
|
||||
return ios;
|
||||
case TargetPlatform.macOS:
|
||||
return macos;
|
||||
case TargetPlatform.windows:
|
||||
return windows;
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions web = FirebaseOptions(
|
||||
apiKey: 'AIzaSyCVEvKsJYzhWDFM-9Od68FE0nPpP933st0',
|
||||
appId: '1:427332280600:web:ad50516a87a35a1a0c7e6d',
|
||||
messagingSenderId: '427332280600',
|
||||
projectId: 'test2-8a3d2',
|
||||
authDomain: 'test2-8a3d2.firebaseapp.com',
|
||||
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||
measurementId: 'G-Z1RTTTV5H9',
|
||||
);
|
||||
|
||||
static const FirebaseOptions android = FirebaseOptions(
|
||||
apiKey: 'AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0',
|
||||
appId: '1:427332280600:android:2bc36fbe82994a3e0c7e6d',
|
||||
messagingSenderId: '427332280600',
|
||||
projectId: 'test2-8a3d2',
|
||||
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||
);
|
||||
|
||||
static const FirebaseOptions ios = FirebaseOptions(
|
||||
apiKey: 'AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw',
|
||||
appId: '1:427332280600:ios:14346b200780dc760c7e6d',
|
||||
messagingSenderId: '427332280600',
|
||||
projectId: 'test2-8a3d2',
|
||||
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||
iosBundleId: 'com.example.syncrowWeb',
|
||||
);
|
||||
|
||||
static const FirebaseOptions macos = FirebaseOptions(
|
||||
apiKey: 'AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw',
|
||||
appId: '1:427332280600:ios:14346b200780dc760c7e6d',
|
||||
messagingSenderId: '427332280600',
|
||||
projectId: 'test2-8a3d2',
|
||||
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||
iosBundleId: 'com.example.syncrowWeb',
|
||||
);
|
||||
|
||||
static const FirebaseOptions windows = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDizKjPC5rdkEjDxwXjM-RU5unB0Ziq3iw',
|
||||
appId: '1:427332280600:web:f7a25537ccd5a7bd0c7e6d',
|
||||
messagingSenderId: '427332280600',
|
||||
projectId: 'test2-8a3d2',
|
||||
authDomain: 'test2-8a3d2.firebaseapp.com',
|
||||
databaseURL: 'https://test2-8a3d2-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'test2-8a3d2.firebasestorage.app',
|
||||
measurementId: 'G-4LFVXEXWKY',
|
||||
);
|
||||
}
|
77
lib/firebase_options_prod.dart
Normal file
77
lib/firebase_options_prod.dart
Normal file
@ -0,0 +1,77 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptionsStaging {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
return web;
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
return android;
|
||||
case TargetPlatform.iOS:
|
||||
return ios;
|
||||
case TargetPlatform.macOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for macos - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions android = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDP9GpYfLE8gHTj3kZ1hW8fx_FkJqOqSQk',
|
||||
appId: '1:786692570726:android:0ef7079c2b978d4417b7a7',
|
||||
messagingSenderId: '786692570726',
|
||||
projectId: 'syncrow-staging',
|
||||
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'syncrow-staging.appspot.com',
|
||||
);
|
||||
|
||||
static const FirebaseOptions ios = FirebaseOptions(
|
||||
apiKey: 'AIzaSyAWlRiuJ75FMlf2_UDdri1voWKvkaSHtRg',
|
||||
appId: '1:786692570726:ios:455a6fcff77e130f17b7a7',
|
||||
messagingSenderId: '786692570726',
|
||||
projectId: 'syncrow-staging',
|
||||
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'syncrow-staging.appspot.com',
|
||||
iosBundleId: 'com.example.syncrow.app',
|
||||
);
|
||||
|
||||
static const FirebaseOptions web = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDyGaQ3sZhb4meaY6sGke-YglhdhJ2is8Q',
|
||||
appId: '1:786692570726:web:93c931e6701797b317b7a7',
|
||||
messagingSenderId: '786692570726',
|
||||
projectId: 'syncrow-staging',
|
||||
authDomain: 'syncrow-staging.firebaseapp.com',
|
||||
databaseURL: 'https://syncrow-staging-default-rtdb.firebaseio.com',
|
||||
storageBucket: 'syncrow-staging.appspot.com',
|
||||
measurementId: 'G-CZ3J3G6LMQ',
|
||||
);
|
||||
}
|
@ -1,12 +1,17 @@
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/firebase_options_dev.dart';
|
||||
import 'package:syncrow_web/firebase_options_prod.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||
import 'package:syncrow_web/services/locator.dart';
|
||||
import 'package:syncrow_web/utils/app_routes.dart';
|
||||
@ -16,9 +21,12 @@ import 'package:syncrow_web/utils/theme/theme.dart';
|
||||
Future<void> main() async {
|
||||
try {
|
||||
const environment =
|
||||
String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
||||
String.fromEnvironment('FLAVOR', defaultValue: 'production');
|
||||
await dotenv.load(fileName: '.env.$environment');
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptionsStaging.currentPlatform,
|
||||
);
|
||||
initialSetup();
|
||||
} catch (_) {}
|
||||
runApp(MyApp());
|
||||
@ -56,6 +64,9 @@ class MyApp extends StatelessWidget {
|
||||
BlocProvider<RoutineBloc>(
|
||||
create: (context) => RoutineBloc(),
|
||||
),
|
||||
BlocProvider<SpaceTreeBloc>(
|
||||
create: (context) => SpaceTreeBloc()..add(InitialEvent()),
|
||||
),
|
||||
],
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
84
lib/main_dev.dart
Normal file
84
lib/main_dev.dart
Normal file
@ -0,0 +1,84 @@
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/firebase_options_dev.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||
import 'package:syncrow_web/services/locator.dart';
|
||||
import 'package:syncrow_web/utils/app_routes.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:syncrow_web/utils/theme/theme.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
try {
|
||||
const environment =
|
||||
String.fromEnvironment('FLAVOR', defaultValue: 'development');
|
||||
await dotenv.load(fileName: '.env.$environment');
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptionsDev.currentPlatform,
|
||||
);
|
||||
initialSetup();
|
||||
} catch (_) {}
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
MyApp({
|
||||
super.key,
|
||||
});
|
||||
|
||||
final GoRouter _router = GoRouter(
|
||||
initialLocation: RoutesConst.auth,
|
||||
routes: AppRoutes.getRoutes(),
|
||||
redirect: (context, state) async {
|
||||
String checkToken = await AuthBloc.getTokenAndValidate();
|
||||
final loggedIn = checkToken == 'Success';
|
||||
final goingToLogin = state.uri.toString() == RoutesConst.auth;
|
||||
|
||||
if (!loggedIn && !goingToLogin) return RoutesConst.auth;
|
||||
if (loggedIn && goingToLogin) return RoutesConst.home;
|
||||
|
||||
return null;
|
||||
},
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => HomeBloc()..add(const FetchUserInfo())),
|
||||
BlocProvider<VisitorPasswordBloc>(
|
||||
create: (context) => VisitorPasswordBloc(),
|
||||
),
|
||||
BlocProvider<RoutineBloc>(
|
||||
create: (context) => RoutineBloc(),
|
||||
),
|
||||
BlocProvider<SpaceTreeBloc>(
|
||||
create: (context) => SpaceTreeBloc()..add(InitialEvent()),
|
||||
),
|
||||
],
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
scrollBehavior: const MaterialScrollBehavior().copyWith(
|
||||
dragDevices: {
|
||||
PointerDeviceKind.mouse,
|
||||
PointerDeviceKind.touch,
|
||||
PointerDeviceKind.stylus,
|
||||
PointerDeviceKind.unknown,
|
||||
},
|
||||
),
|
||||
theme: myTheme,
|
||||
routerConfig: _router,
|
||||
));
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
|
||||
class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
@ -27,19 +28,19 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
final isLargeScreen = isLargeScreenSize(context);
|
||||
final isSmallScreen = isSmallScreenSize(context);
|
||||
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
||||
final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
||||
final padding =
|
||||
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
||||
|
||||
return WebScaffold(
|
||||
enableMenuSidebar: false,
|
||||
appBarTitle: FittedBox(
|
||||
child: Text(
|
||||
'Access Management',
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
appBarTitle: Text(
|
||||
'Access Management',
|
||||
style: ResponsiveTextTheme.of(context).deviceManagementTitle,
|
||||
),
|
||||
rightBody: const NavigateHomeGridView(),
|
||||
scaffoldBody: BlocProvider(
|
||||
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
|
||||
create: (BuildContext context) =>
|
||||
AccessBloc()..add(FetchTableData()),
|
||||
child: BlocConsumer<AccessBloc, AccessState>(
|
||||
listener: (context, state) {},
|
||||
builder: (context, state) {
|
||||
@ -93,11 +94,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
return [
|
||||
item.passwordName,
|
||||
item.passwordType.value,
|
||||
accessBloc.timestampToDate(item.effectiveTime),
|
||||
accessBloc.timestampToDate(item.invalidTime),
|
||||
accessBloc
|
||||
.timestampToDate(item.effectiveTime),
|
||||
accessBloc
|
||||
.timestampToDate(item.invalidTime),
|
||||
item.deviceName.toString(),
|
||||
item.authorizerEmail.toString(),
|
||||
accessBloc.timestampToDate(item.invalidTime),
|
||||
accessBloc
|
||||
.timestampToDate(item.invalidTime),
|
||||
item.passwordStatus.value,
|
||||
];
|
||||
}).toList(),
|
||||
@ -108,7 +112,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
})));
|
||||
}
|
||||
|
||||
Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) {
|
||||
Wrap _buildVisitorAdminPasswords(
|
||||
BuildContext context, AccessBloc accessBloc) {
|
||||
return Wrap(
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
@ -134,7 +139,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
borderRadius: 8,
|
||||
child: Text(
|
||||
'Create Visitor Password ',
|
||||
style: context.textTheme.titleSmall!.copyWith(color: Colors.white, fontSize: 12),
|
||||
style: context.textTheme.titleSmall!
|
||||
.copyWith(color: Colors.white, fontSize: 12),
|
||||
)),
|
||||
),
|
||||
// Container(
|
||||
@ -172,8 +178,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
description: '',
|
||||
onSubmitted: (value) {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
emailAuthorizer:
|
||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
@ -191,8 +199,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
description: '',
|
||||
onSubmitted: (value) {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
emailAuthorizer:
|
||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
@ -221,7 +231,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
onSearch: () {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
@ -249,8 +260,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
description: '',
|
||||
onSubmitted: (value) {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
emailAuthorizer:
|
||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
@ -274,7 +287,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
onSearch: () {
|
||||
accessBloc.add(FilterDataEvent(
|
||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
selectedTabIndex:
|
||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||
endTime: accessBloc.expirationTimeTimeStamp));
|
||||
|
@ -31,7 +31,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
|
||||
////////////////////////////// forget password //////////////////////////////////
|
||||
final TextEditingController forgetEmailController = TextEditingController();
|
||||
final TextEditingController forgetPasswordController = TextEditingController();
|
||||
final TextEditingController forgetPasswordController =
|
||||
TextEditingController();
|
||||
final TextEditingController forgetOtp = TextEditingController();
|
||||
final forgetFormKey = GlobalKey<FormState>();
|
||||
final forgetEmailKey = GlobalKey<FormState>();
|
||||
@ -48,7 +49,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
return;
|
||||
}
|
||||
_remainingTime = 1;
|
||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
add(UpdateTimerEvent(
|
||||
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
try {
|
||||
forgetEmailValidate = '';
|
||||
_remainingTime = (await AuthenticationAPI.sendOtp(
|
||||
@ -85,7 +87,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
_timer?.cancel();
|
||||
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
||||
} else {
|
||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
add(UpdateTimerEvent(
|
||||
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -95,7 +98,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
||||
}
|
||||
|
||||
Future<void> changePassword(ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||
Future<void> changePassword(
|
||||
ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||
emit(LoadingForgetState());
|
||||
try {
|
||||
var response = await AuthenticationAPI.verifyOtp(
|
||||
@ -111,7 +115,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['error']['message'] ?? 'something went wrong';
|
||||
String errorMessage =
|
||||
errorData['error']['message'] ?? 'something went wrong';
|
||||
validate = errorMessage;
|
||||
emit(AuthInitialState());
|
||||
}
|
||||
@ -125,7 +130,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
|
||||
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
||||
emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime));
|
||||
emit(TimerState(
|
||||
isButtonEnabled: event.isButtonEnabled,
|
||||
remainingTime: event.remainingTime));
|
||||
}
|
||||
|
||||
///////////////////////////////////// login /////////////////////////////////////
|
||||
@ -161,15 +168,23 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
password: event.password,
|
||||
),
|
||||
);
|
||||
} catch (failure) {
|
||||
validate = 'Invalid Credentials!';
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['error']['message'];
|
||||
if (errorMessage == "Access denied for web platform") {
|
||||
validate = errorMessage;
|
||||
} else {
|
||||
validate = 'Invalid Credentials!';
|
||||
}
|
||||
emit(LoginInitial());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (token.accessTokenIsNotEmpty) {
|
||||
FlutterSecureStorage storage = const FlutterSecureStorage();
|
||||
await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||
await storage.write(
|
||||
key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||
const FlutterSecureStorage().write(
|
||||
key: UserModel.userUuidKey,
|
||||
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
||||
@ -327,12 +342,14 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
static Future<String> getTokenAndValidate() async {
|
||||
try {
|
||||
const storage = FlutterSecureStorage();
|
||||
final firstLaunch =
|
||||
await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
|
||||
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
|
||||
StringsManager.firstLaunch) ??
|
||||
true;
|
||||
if (firstLaunch) {
|
||||
storage.deleteAll();
|
||||
}
|
||||
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
|
||||
await SharedPreferencesHelper.saveBoolToSP(
|
||||
StringsManager.firstLaunch, false);
|
||||
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
||||
if (value.isEmpty) {
|
||||
return 'Token not found';
|
||||
@ -385,7 +402,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final String formattedTime = [
|
||||
if (days > 0) '${days}d', // Append 'd' for days
|
||||
if (days > 0 || hours > 0)
|
||||
hours.toString().padLeft(2, '0'), // Show hours if there are days or hours
|
||||
hours
|
||||
.toString()
|
||||
.padLeft(2, '0'), // Show hours if there are days or hours
|
||||
minutes.toString().padLeft(2, '0'),
|
||||
seconds.toString().padLeft(2, '0'),
|
||||
].join(':');
|
||||
|
@ -21,7 +21,9 @@ class LoginWithEmailModel {
|
||||
return {
|
||||
'email': email,
|
||||
'password': password,
|
||||
"platform": "web"
|
||||
// 'regionUuid': regionUuid,
|
||||
};
|
||||
}
|
||||
}
|
||||
//tst@tst.com
|
@ -10,6 +10,10 @@ class UserModel {
|
||||
final String? phoneNumber;
|
||||
final bool? isEmailVerified;
|
||||
final bool? isAgreementAccepted;
|
||||
final bool? hasAcceptedWebAgreement;
|
||||
final DateTime? webAgreementAcceptedAt;
|
||||
final UserRole? role;
|
||||
|
||||
UserModel({
|
||||
required this.uuid,
|
||||
required this.email,
|
||||
@ -19,6 +23,9 @@ class UserModel {
|
||||
required this.phoneNumber,
|
||||
required this.isEmailVerified,
|
||||
required this.isAgreementAccepted,
|
||||
required this.hasAcceptedWebAgreement,
|
||||
required this.webAgreementAcceptedAt,
|
||||
required this.role,
|
||||
});
|
||||
|
||||
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||
@ -31,6 +38,11 @@ class UserModel {
|
||||
phoneNumber: json['phoneNumber'],
|
||||
isEmailVerified: json['isEmailVerified'],
|
||||
isAgreementAccepted: json['isAgreementAccepted'],
|
||||
hasAcceptedWebAgreement: json['hasAcceptedWebAgreement'],
|
||||
webAgreementAcceptedAt: json['webAgreementAcceptedAt'] != null
|
||||
? DateTime.parse(json['webAgreementAcceptedAt'])
|
||||
: null,
|
||||
role: json['role'] != null ? UserRole.fromJson(json['role']) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -41,6 +53,9 @@ class UserModel {
|
||||
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
|
||||
|
||||
return UserModel(
|
||||
hasAcceptedWebAgreement: null,
|
||||
role: null,
|
||||
webAgreementAcceptedAt: null,
|
||||
uuid: tempJson['uuid'].toString(),
|
||||
email: tempJson['email'],
|
||||
firstName: null,
|
||||
@ -65,3 +80,26 @@ class UserModel {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class UserRole {
|
||||
final String uuid;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
final String type;
|
||||
|
||||
UserRole({
|
||||
required this.uuid,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
factory UserRole.fromJson(Map<String, dynamic> json) {
|
||||
return UserRole(
|
||||
uuid: json['uuid'],
|
||||
createdAt: DateTime.parse(json['createdAt']),
|
||||
updatedAt: DateTime.parse(json['updatedAt']),
|
||||
type: json['type'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ class ForgetPasswordPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const ResponsiveLayout(
|
||||
desktopBody: ForgetPasswordWebPage(), mobileBody: ForgetPasswordWebPage());
|
||||
tablet: ForgetPasswordWebPage(),
|
||||
desktopBody: ForgetPasswordWebPage(),
|
||||
mobileBody: ForgetPasswordWebPage());
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ class LoginPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const ResponsiveLayout(
|
||||
desktopBody: LoginWebPage(), mobileBody: LoginWebPage());
|
||||
tablet: LoginWebPage(),
|
||||
desktopBody: LoginWebPage(),
|
||||
mobileBody: LoginWebPage());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
@ -19,6 +20,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
on<AcControlEvent>(_onAcControl);
|
||||
on<AcBatchControlEvent>(_onAcBatchControl);
|
||||
on<AcFactoryResetEvent>(_onFactoryReset);
|
||||
on<AcStatusUpdated>(_onAcStatusUpdated);
|
||||
}
|
||||
|
||||
FutureOr<void> _onFetchAcStatus(
|
||||
@ -28,12 +30,64 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
|
||||
_listenToChanges(event.deviceId);
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) async {
|
||||
if (event.snapshot.value == null) return;
|
||||
|
||||
if (_timer != null) {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
}
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus =
|
||||
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(AcStatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onAcStatusUpdated(AcStatusUpdated event, Emitter<AcsState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
// Future<void> testFirebaseConnection() async {
|
||||
// // Reference to a test node in your database
|
||||
// final testRef = FirebaseDatabase.instance.ref("test");
|
||||
|
||||
// // Write a test value
|
||||
// await testRef.set("Hello, Firebase!");
|
||||
|
||||
// // Listen for changes on the test node
|
||||
// testRef.onValue.listen((DatabaseEvent event) {
|
||||
// final data = event.snapshot.value;
|
||||
// print("Data from Firebase: $data");
|
||||
// // If you see "Hello, Firebase!" printed in your console, it means the connection works.
|
||||
// });
|
||||
// }
|
||||
|
||||
FutureOr<void> _onAcControl(
|
||||
AcControlEvent event, Emitter<AcsState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
|
||||
sealed class AcsEvent extends Equatable {
|
||||
@ -7,6 +8,7 @@ sealed class AcsEvent extends Equatable {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
class AcUpdated extends AcsEvent {}
|
||||
|
||||
class AcFetchDeviceStatusEvent extends AcsEvent {
|
||||
final String deviceId;
|
||||
@ -16,7 +18,10 @@ class AcFetchDeviceStatusEvent extends AcsEvent {
|
||||
@override
|
||||
List<Object> get props => [deviceId];
|
||||
}
|
||||
|
||||
class AcStatusUpdated extends AcsEvent {
|
||||
final AcStatusModel deviceStatus;
|
||||
AcStatusUpdated(this.deviceStatus);
|
||||
}
|
||||
class AcFetchBatchStatusEvent extends AcsEvent {
|
||||
final List<String> devicesIds;
|
||||
|
||||
|
@ -24,7 +24,8 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
final isLarge = isLargeScreenSize(context);
|
||||
final isMedium = isMediumScreenSize(context);
|
||||
return BlocProvider(
|
||||
create: (context) => AcBloc(deviceId: device.uuid!)..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
||||
create: (context) => AcBloc(deviceId: device.uuid!)
|
||||
..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
||||
child: BlocBuilder<AcBloc, AcsState>(
|
||||
builder: (context, state) {
|
||||
if (state is ACStatusLoaded) {
|
||||
@ -98,7 +99,8 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
),
|
||||
Text(
|
||||
'h',
|
||||
style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor),
|
||||
style: context.textTheme.bodySmall!
|
||||
.copyWith(color: ColorsManager.blackColor),
|
||||
),
|
||||
Text(
|
||||
'30',
|
||||
@ -107,7 +109,9 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)),
|
||||
Text('m',
|
||||
style: context.textTheme.bodySmall!
|
||||
.copyWith(color: ColorsManager.blackColor)),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {},
|
||||
|
@ -1,13 +1,14 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
|
||||
part 'device_managment_event.dart';
|
||||
part 'device_managment_state.dart';
|
||||
|
||||
class DeviceManagementBloc
|
||||
extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
int _selectedIndex = 0;
|
||||
List<AllDevicesModel> _devices = [];
|
||||
int _onlineCount = 0;
|
||||
@ -30,11 +31,23 @@ class DeviceManagementBloc
|
||||
on<UpdateSelection>(_onUpdateSelection);
|
||||
}
|
||||
|
||||
Future<void> _onFetchDevices(
|
||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
Future<void> _onFetchDevices(FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
emit(DeviceManagementLoading());
|
||||
try {
|
||||
final devices = await DevicesManagementApi().fetchDevices();
|
||||
List<AllDevicesModel> devices = [];
|
||||
_devices.clear();
|
||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||
devices = await DevicesManagementApi().fetchDevices('', '');
|
||||
} else {
|
||||
for (var community in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
||||
for (var space in spacesList) {
|
||||
devices.addAll(await DevicesManagementApi().fetchDevices(community, space));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_selectedDevices.clear();
|
||||
_devices = devices;
|
||||
_filteredDevices = devices;
|
||||
@ -53,8 +66,7 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
void _onFilterDevices(
|
||||
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
void _onFilterDevices(FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||
if (_devices.isNotEmpty) {
|
||||
_filteredDevices = List.from(_devices.where((device) {
|
||||
switch (event.filter) {
|
||||
@ -85,8 +97,7 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onResetFilters(
|
||||
ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
||||
Future<void> _onResetFilters(ResetFilters event, Emitter<DeviceManagementState> emit) async {
|
||||
currentProductName = '';
|
||||
_selectedDevices.clear();
|
||||
_filteredDevices = List.from(_devices);
|
||||
@ -102,8 +113,7 @@ class DeviceManagementBloc
|
||||
));
|
||||
}
|
||||
|
||||
void _onResetSelectedDevices(
|
||||
ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
||||
void _onResetSelectedDevices(ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedDevices.clear();
|
||||
|
||||
if (state is DeviceManagementLoaded) {
|
||||
@ -129,14 +139,12 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
void _onSelectedFilterChanged(
|
||||
SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSelectedFilterChanged(SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
|
||||
_selectedIndex = event.selectedIndex;
|
||||
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
||||
}
|
||||
|
||||
void _onSelectDevice(
|
||||
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||
final selectedUuid = event.selectedDevice.uuid;
|
||||
|
||||
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
||||
@ -147,8 +155,7 @@ class DeviceManagementBloc
|
||||
|
||||
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
|
||||
|
||||
bool isControlButtonEnabled =
|
||||
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||
bool isControlButtonEnabled = _checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||
|
||||
if (state is DeviceManagementLoaded) {
|
||||
emit(DeviceManagementLoaded(
|
||||
@ -157,8 +164,7 @@ class DeviceManagementBloc
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
selectedDevice:
|
||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
isControlButtonEnabled: isControlButtonEnabled,
|
||||
));
|
||||
} else if (state is DeviceManagementFiltered) {
|
||||
@ -168,15 +174,13 @@ class DeviceManagementBloc
|
||||
onlineCount: _onlineCount,
|
||||
offlineCount: _offlineCount,
|
||||
lowBatteryCount: _lowBatteryCount,
|
||||
selectedDevice:
|
||||
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
|
||||
isControlButtonEnabled: isControlButtonEnabled,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateSelection(
|
||||
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||
void _onUpdateSelection(UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||
List<AllDevicesModel> selectedDevices = [];
|
||||
List<AllDevicesModel> devicesToSelectFrom = [];
|
||||
|
||||
@ -219,8 +223,7 @@ class DeviceManagementBloc
|
||||
|
||||
bool _checkIfControlButtonEnabled(List<AllDevicesModel> selectedDevices) {
|
||||
if (selectedDevices.length > 1) {
|
||||
final productTypes =
|
||||
selectedDevices.map((device) => device.productType).toSet();
|
||||
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
||||
return productTypes.length == 1;
|
||||
} else if (selectedDevices.length == 1) {
|
||||
return true;
|
||||
@ -231,10 +234,8 @@ class DeviceManagementBloc
|
||||
void _calculateDeviceCounts() {
|
||||
_onlineCount = _devices.where((device) => device.online == true).length;
|
||||
_offlineCount = _devices.where((device) => device.online == false).length;
|
||||
_lowBatteryCount = _devices
|
||||
.where((device) =>
|
||||
device.batteryLevel != null && device.batteryLevel! < 20)
|
||||
.length;
|
||||
_lowBatteryCount =
|
||||
_devices.where((device) => device.batteryLevel != null && device.batteryLevel! < 20).length;
|
||||
}
|
||||
|
||||
String _getFilterFromIndex(int index) {
|
||||
@ -250,8 +251,7 @@ class DeviceManagementBloc
|
||||
}
|
||||
}
|
||||
|
||||
void _onSearchDevices(
|
||||
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||
if ((event.community == null || event.community!.isEmpty) &&
|
||||
(event.unitName == null || event.unitName!.isEmpty) &&
|
||||
(event.productName == null || event.productName!.isEmpty)) {
|
||||
@ -280,33 +280,22 @@ class DeviceManagementBloc
|
||||
final filteredDevices = devicesToSearch.where((device) {
|
||||
final matchesCommunity = event.community == null ||
|
||||
event.community!.isEmpty ||
|
||||
(device.community?.name
|
||||
?.toLowerCase()
|
||||
.contains(event.community!.toLowerCase()) ??
|
||||
(device.community?.name?.toLowerCase().contains(event.community!.toLowerCase()) ??
|
||||
false);
|
||||
final matchesUnit = event.unitName == null ||
|
||||
event.unitName!.isEmpty ||
|
||||
(device.spaces != null &&
|
||||
device.spaces!.isNotEmpty &&
|
||||
device.spaces![0].spaceName
|
||||
!.toLowerCase()
|
||||
.contains(event.unitName!.toLowerCase()));
|
||||
device.spaces![0].spaceName!.toLowerCase().contains(event.unitName!.toLowerCase()));
|
||||
final matchesProductName = event.productName == null ||
|
||||
event.productName!.isEmpty ||
|
||||
(device.name
|
||||
?.toLowerCase()
|
||||
.contains(event.productName!.toLowerCase()) ??
|
||||
false);
|
||||
(device.name?.toLowerCase().contains(event.productName!.toLowerCase()) ?? false);
|
||||
final matchesDeviceName = event.productName == null ||
|
||||
event.productName!.isEmpty ||
|
||||
(device.categoryName
|
||||
?.toLowerCase()
|
||||
.contains(event.productName!.toLowerCase()) ??
|
||||
(device.categoryName?.toLowerCase().contains(event.productName!.toLowerCase()) ??
|
||||
false);
|
||||
|
||||
return matchesCommunity &&
|
||||
matchesUnit &&
|
||||
(matchesProductName || matchesDeviceName);
|
||||
return matchesCommunity && matchesUnit && (matchesProductName || matchesDeviceName);
|
||||
}).toList();
|
||||
|
||||
emit(DeviceManagementFiltered(
|
||||
|
@ -7,7 +7,15 @@ abstract class DeviceManagementEvent extends Equatable {
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class FetchDevices extends DeviceManagementEvent {}
|
||||
class FetchDevices extends DeviceManagementEvent {
|
||||
// final Map<String, List<String>> selectedCommunitiesSpaces;
|
||||
// final String spaceId;
|
||||
final BuildContext context;
|
||||
|
||||
const FetchDevices(this.context);
|
||||
@override
|
||||
List<Object?> get props => [context];
|
||||
}
|
||||
|
||||
class FilterDevices extends DeviceManagementEvent {
|
||||
final String filter;
|
||||
|
@ -3,11 +3,11 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_spa
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/enum/device_types.dart';
|
||||
|
||||
@ -148,9 +148,7 @@ class AllDevicesModel {
|
||||
|
||||
productName = json['productName']?.toString();
|
||||
if (json['spaces'] != null && json['spaces'] is List) {
|
||||
spaces = (json['spaces'] as List)
|
||||
.map((space) => DeviceSpaceModel.fromJson(space))
|
||||
.toList();
|
||||
spaces = (json['spaces'] as List).map((space) => DeviceSpaceModel.fromJson(space)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,8 +196,7 @@ SOS
|
||||
String tempIcon = '';
|
||||
if (type == DeviceType.LightBulb) {
|
||||
tempIcon = Assets.lightBulb;
|
||||
} else if (type == DeviceType.CeilingSensor ||
|
||||
type == DeviceType.WallSensor) {
|
||||
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||
tempIcon = Assets.sensors;
|
||||
} else if (type == DeviceType.AC) {
|
||||
tempIcon = Assets.ac;
|
||||
@ -254,34 +251,25 @@ SOS
|
||||
case '1G':
|
||||
return [
|
||||
OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
OneGangCountdownFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
OneGangCountdownFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
case '2G':
|
||||
return [
|
||||
TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
case '3G':
|
||||
return [
|
||||
ThreeGangSwitch1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch3Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown3Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangSwitch3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
ThreeGangCountdown3Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
default:
|
||||
|
@ -3,12 +3,13 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/routines_view.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/view/create_new_routine_view.dart';
|
||||
import 'package:syncrow_web/pages/routines/view/routines_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
|
||||
class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
@ -19,17 +20,17 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
|
||||
create: (context) =>
|
||||
DeviceManagementBloc()..add(FetchDevices(context)),
|
||||
),
|
||||
],
|
||||
child: WebScaffold(
|
||||
appBarTitle: FittedBox(
|
||||
child: Text(
|
||||
'Device Management',
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
appBarTitle: Text(
|
||||
'Device Management',
|
||||
style: ResponsiveTextTheme.of(context).deviceManagementTitle,
|
||||
),
|
||||
centerBody: BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
||||
centerBody:
|
||||
BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@ -45,8 +46,11 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
child: Text(
|
||||
'Devices',
|
||||
style: context.textTheme.titleMedium?.copyWith(
|
||||
color: !state.routineTab ? ColorsManager.whiteColors : ColorsManager.grayColor,
|
||||
fontWeight: !state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
||||
color: !state.routineTab
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.grayColor,
|
||||
fontWeight:
|
||||
!state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -55,13 +59,18 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
backgroundColor: null,
|
||||
),
|
||||
onPressed: () {
|
||||
context.read<RoutineBloc>().add(const TriggerSwitchTabsEvent(isRoutineTab: true));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: true));
|
||||
},
|
||||
child: Text(
|
||||
'Routines',
|
||||
style: context.textTheme.titleMedium?.copyWith(
|
||||
color: state.routineTab ? ColorsManager.whiteColors : ColorsManager.grayColor,
|
||||
fontWeight: state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
||||
color: state.routineTab
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.grayColor,
|
||||
fontWeight:
|
||||
state.routineTab ? FontWeight.w700 : FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -69,7 +78,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
);
|
||||
}),
|
||||
rightBody: const NavigateHomeGridView(),
|
||||
scaffoldBody: BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
||||
scaffoldBody:
|
||||
BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
|
||||
if (state.routineTab) {
|
||||
return const RoutinesView();
|
||||
}
|
||||
@ -80,11 +90,12 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
builder: (context, deviceState) {
|
||||
if (deviceState is DeviceManagementLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return const DeviceManagementBody(devices: []);
|
||||
} else if (deviceState is DeviceManagementLoaded) {
|
||||
return DeviceManagementBody(devices: deviceState.devices);
|
||||
} else if (deviceState is DeviceManagementFiltered) {
|
||||
return DeviceManagementBody(devices: deviceState.filteredDevices);
|
||||
return DeviceManagementBody(
|
||||
devices: deviceState.filteredDevices);
|
||||
} else {
|
||||
return const Center(child: Text('Error fetching Devices'));
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
@ -59,118 +60,153 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
|
||||
final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
|
||||
|
||||
return Column(
|
||||
return Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FilterWidget(
|
||||
size: MediaQuery.of(context).size,
|
||||
tabs: tabs,
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChanged: (index) {
|
||||
context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const DeviceSearchFilters(),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
height: 45,
|
||||
width: 125,
|
||||
decoration: containerDecoration,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: isControlButtonEnabled
|
||||
? () {
|
||||
if (selectedDevices.length == 1) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => DeviceControlDialog(
|
||||
device: selectedDevices.first,
|
||||
),
|
||||
);
|
||||
} else if (selectedDevices.length > 1) {
|
||||
final productTypes = selectedDevices.map((device) => device.productType).toSet();
|
||||
if (productTypes.length == 1) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => DeviceBatchControlDialog(
|
||||
devices: selectedDevices,
|
||||
Expanded(child: SpaceTreeView(
|
||||
onSelect: () {
|
||||
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||
},
|
||||
)),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: state is DeviceManagementLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: isLargeScreenSize(context)
|
||||
? const EdgeInsets.all(30)
|
||||
: const EdgeInsets.all(15),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FilterWidget(
|
||||
size: MediaQuery.of(context).size,
|
||||
tabs: tabs,
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChanged: (index) {
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(SelectedFilterChanged(index));
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const DeviceSearchFilters(),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
// height: 45,
|
||||
width: 125,
|
||||
decoration: containerDecoration,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: isControlButtonEnabled
|
||||
? () {
|
||||
if (selectedDevices.length == 1) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => DeviceControlDialog(
|
||||
device: selectedDevices.first,
|
||||
),
|
||||
);
|
||||
} else if (selectedDevices.length > 1) {
|
||||
final productTypes = selectedDevices
|
||||
.map((device) => device.productType)
|
||||
.toSet();
|
||||
if (productTypes.length == 1) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => DeviceBatchControlDialog(
|
||||
devices: selectedDevices,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
borderRadius: 9,
|
||||
child: Text(
|
||||
buttonLabel,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isControlButtonEnabled ? Colors.white : Colors.grey,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
borderRadius: 9,
|
||||
child: Text(
|
||||
buttonLabel,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isControlButtonEnabled ? Colors.white : Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
|
||||
child: DynamicTable(
|
||||
withSelectAll: true,
|
||||
cellDecoration: containerDecoration,
|
||||
onRowSelected: (index, isSelected, row) {
|
||||
final selectedDevice = devicesToShow[index];
|
||||
context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
|
||||
},
|
||||
withCheckBox: true,
|
||||
size: MediaQuery.of(context).size,
|
||||
uuidIndex: 2,
|
||||
headers: const [
|
||||
'Device Name',
|
||||
'Product Name',
|
||||
'Device ID',
|
||||
'Space Name',
|
||||
'location',
|
||||
'Battery Level',
|
||||
'Installation Date and Time',
|
||||
'Status',
|
||||
'Last Offline Date and Time',
|
||||
],
|
||||
data: devicesToShow.map((device) {
|
||||
final combinedSpaceNames = device.spaces != null
|
||||
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
||||
(device.community != null ? ' > ${device.community!.name}' : '')
|
||||
: (device.community != null ? device.community!.name : '');
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: isLargeScreenSize(context)
|
||||
? const EdgeInsets.all(30)
|
||||
: const EdgeInsets.all(15),
|
||||
child: DynamicTable(
|
||||
withSelectAll: true,
|
||||
cellDecoration: containerDecoration,
|
||||
onRowSelected: (index, isSelected, row) {
|
||||
final selectedDevice = devicesToShow[index];
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(SelectDevice(selectedDevice));
|
||||
},
|
||||
withCheckBox: true,
|
||||
size: MediaQuery.of(context).size,
|
||||
uuidIndex: 2,
|
||||
headers: const [
|
||||
'Device Name',
|
||||
'Product Name',
|
||||
'Device ID',
|
||||
'Space Name',
|
||||
'location',
|
||||
'Battery Level',
|
||||
'Installation Date and Time',
|
||||
'Status',
|
||||
'Last Offline Date and Time',
|
||||
],
|
||||
data: devicesToShow.map((device) {
|
||||
final combinedSpaceNames = device.spaces != null
|
||||
? device.spaces!.map((space) => space.spaceName).join(' > ') +
|
||||
(device.community != null
|
||||
? ' > ${device.community!.name}'
|
||||
: '')
|
||||
: (device.community != null ? device.community!.name : '');
|
||||
|
||||
return [
|
||||
device.name ?? '',
|
||||
device.productName ?? '',
|
||||
device.uuid ?? '',
|
||||
(device.spaces != null && device.spaces!.isNotEmpty) ? device.spaces![0].spaceName : '',
|
||||
combinedSpaceNames,
|
||||
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
|
||||
device.online == true ? 'Online' : 'Offline',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
|
||||
];
|
||||
}).toList(),
|
||||
onSelectionChanged: (selectedRows) {
|
||||
context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
|
||||
},
|
||||
initialSelectedIds:
|
||||
context.read<DeviceManagementBloc>().selectedDevices.map((device) => device.uuid!).toList(),
|
||||
isEmpty: devicesToShow.isEmpty,
|
||||
),
|
||||
),
|
||||
)
|
||||
return [
|
||||
device.name ?? '',
|
||||
device.productName ?? '',
|
||||
device.uuid ?? '',
|
||||
(device.spaces != null && device.spaces!.isNotEmpty)
|
||||
? device.spaces![0].spaceName
|
||||
: '',
|
||||
combinedSpaceNames,
|
||||
device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
(device.createTime ?? 0) * 1000)),
|
||||
device.online == true ? 'Online' : 'Offline',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
(device.updateTime ?? 0) * 1000)),
|
||||
];
|
||||
}).toList(),
|
||||
onSelectionChanged: (selectedRows) {
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(UpdateSelection(selectedRows));
|
||||
},
|
||||
initialSelectedIds: context
|
||||
.read<DeviceManagementBloc>()
|
||||
.selectedDevices
|
||||
.map((device) => device.uuid!)
|
||||
.toList(),
|
||||
isEmpty: devicesToShow.isEmpty,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -12,8 +12,7 @@ class DeviceSearchFilters extends StatefulWidget {
|
||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||
}
|
||||
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
with HelperResponsiveLayout {
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
||||
final TextEditingController communityController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController productNameController = TextEditingController();
|
||||
@ -27,8 +26,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Space Name", unitNameController, 200),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField(
|
||||
"Device Name / Product Name", productNameController, 300),
|
||||
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchResetButtons(),
|
||||
],
|
||||
@ -53,8 +51,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchField(
|
||||
String title, TextEditingController controller, double width) {
|
||||
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
||||
return Container(
|
||||
child: StatefulTextField(
|
||||
title: title,
|
||||
@ -88,7 +85,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
productNameController.clear();
|
||||
context.read<DeviceManagementBloc>()
|
||||
..add(ResetFilters())
|
||||
..add(FetchDevices());
|
||||
..add(FetchDevices(context));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
|
||||
@ -22,42 +23,55 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
||||
on<ShowCeilingDescriptionEvent>(_showDescription);
|
||||
on<BackToCeilingGridViewEvent>(_backToGridView);
|
||||
on<CeilingFactoryResetEvent>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
void _fetchCeilingSensorStatus(
|
||||
CeilingInitialEvent event, Emitter<CeilingSensorState> emit) async {
|
||||
emit(CeilingLoadingInitialState());
|
||||
try {
|
||||
var response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
var response =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||
// _listenToChanges();
|
||||
_listenToChanges(event.deviceId);
|
||||
} catch (e) {
|
||||
emit(CeilingFailedState(error: e.toString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// _listenToChanges() {
|
||||
// try {
|
||||
// DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
// Stream<DatabaseEvent> stream = ref.onValue;
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
// stream.listen((DatabaseEvent event) {
|
||||
// Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||
// List<StatusModel> statusList = [];
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
// usersMap['status'].forEach((element) {
|
||||
// statusList.add(StatusModel(code: element['code'], value: element['value']));
|
||||
// });
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
// deviceStatus = WallSensorModel.fromJson(statusList);
|
||||
// add(WallSensorUpdatedEvent());
|
||||
// });
|
||||
// } catch (_) {}
|
||||
// }
|
||||
deviceStatus = CeilingSensorModel.fromJson(statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _changeValue(CeilingChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<CeilingSensorState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||
}
|
||||
|
||||
void _changeValue(
|
||||
CeilingChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
|
||||
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
|
||||
if (event.code == 'sensitivity') {
|
||||
deviceStatus.sensitivity = event.value;
|
||||
@ -122,7 +136,8 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
||||
try {
|
||||
late bool response;
|
||||
if (isBatch) {
|
||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
||||
response = await DevicesManagementApi()
|
||||
.deviceBatchControl(deviceId, code, value);
|
||||
} else {
|
||||
response = await DevicesManagementApi()
|
||||
.deviceControl(deviceId, Status(code: code, value: value));
|
||||
@ -143,8 +158,8 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
||||
});
|
||||
}
|
||||
|
||||
FutureOr<void> _getDeviceReports(
|
||||
GetCeilingDeviceReportsEvent event, Emitter<CeilingSensorState> emit) async {
|
||||
FutureOr<void> _getDeviceReports(GetCeilingDeviceReportsEvent event,
|
||||
Emitter<CeilingSensorState> emit) async {
|
||||
if (event.code.isEmpty) {
|
||||
emit(ShowCeilingDescriptionState(description: reportString));
|
||||
return;
|
||||
@ -155,7 +170,8 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
||||
|
||||
try {
|
||||
// await DevicesManagementApi.getDeviceReportsByDate(deviceId, event.code, from.toString(), to.toString())
|
||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code).then((value) {
|
||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code)
|
||||
.then((value) {
|
||||
emit(CeilingReportsState(deviceReport: value));
|
||||
});
|
||||
} catch (e) {
|
||||
@ -165,19 +181,23 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _showDescription(ShowCeilingDescriptionEvent event, Emitter<CeilingSensorState> emit) {
|
||||
void _showDescription(
|
||||
ShowCeilingDescriptionEvent event, Emitter<CeilingSensorState> emit) {
|
||||
emit(ShowCeilingDescriptionState(description: event.description));
|
||||
}
|
||||
|
||||
void _backToGridView(BackToCeilingGridViewEvent event, Emitter<CeilingSensorState> emit) {
|
||||
void _backToGridView(
|
||||
BackToCeilingGridViewEvent event, Emitter<CeilingSensorState> emit) {
|
||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||
}
|
||||
|
||||
FutureOr<void> _fetchCeilingSensorBatchControl(
|
||||
CeilingFetchDeviceStatusEvent event, Emitter<CeilingSensorState> emit) async {
|
||||
CeilingFetchDeviceStatusEvent event,
|
||||
Emitter<CeilingSensorState> emit) async {
|
||||
emit(CeilingLoadingInitialState());
|
||||
try {
|
||||
var response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||
var response =
|
||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||
deviceStatus = CeilingSensorModel.fromJson(response.status);
|
||||
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
|
||||
} catch (e) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
|
||||
|
||||
abstract class CeilingSensorEvent extends Equatable {
|
||||
const CeilingSensorEvent();
|
||||
@ -83,3 +84,12 @@ class CeilingFactoryResetEvent extends CeilingSensorEvent {
|
||||
@override
|
||||
List<Object> get props => [devicesId, factoryResetModel];
|
||||
}
|
||||
|
||||
|
||||
|
||||
class StatusUpdated extends CeilingSensorEvent {
|
||||
final CeilingSensorModel deviceStatus;
|
||||
const StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/curtain/bloc/curtain_event.dart';
|
||||
@ -16,6 +17,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
||||
on<CurtainControl>(_onCurtainControl);
|
||||
on<CurtainBatchControl>(_onCurtainBatchControl);
|
||||
on<CurtainFactoryReset>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
FutureOr<void> _onFetchDeviceStatus(
|
||||
@ -24,7 +26,7 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
||||
try {
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
|
||||
_listenToChanges(event.deviceId);
|
||||
deviceStatus = _checkStatus(status.status[0].value);
|
||||
|
||||
emit(CurtainStatusLoaded(deviceStatus));
|
||||
@ -33,6 +35,48 @@ class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _listenToChanges(String deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||
if (data == null) return;
|
||||
|
||||
List<Status> statusList = [];
|
||||
if (data['status'] != null) {
|
||||
for (var element in data['status']) {
|
||||
statusList.add(
|
||||
Status(
|
||||
code: element['code'].toString(),
|
||||
value: element['value'].toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (statusList.isNotEmpty) {
|
||||
bool newStatus = _checkStatus(statusList[0].value);
|
||||
if (newStatus != deviceStatus) {
|
||||
deviceStatus = newStatus;
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
emit(CurtainError('Failed to listen to changes: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<CurtainState> emit) {
|
||||
emit(CurtainStatusLoading());
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(CurtainStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
FutureOr<void> _onCurtainControl(
|
||||
CurtainControl event, Emitter<CurtainState> emit) async {
|
||||
final oldValue = deviceStatus;
|
||||
|
@ -60,3 +60,7 @@ class CurtainFactoryReset extends CurtainEvent {
|
||||
@override
|
||||
List<Object> get props => [deviceId, factoryReset];
|
||||
}
|
||||
class StatusUpdated extends CurtainEvent {
|
||||
final bool deviceStatus;
|
||||
const StatusUpdated(this.deviceStatus);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/bloc/door_lock_event.dart';
|
||||
@ -18,6 +19,39 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
||||
//on<DoorLockControl>(_onDoorLockControl);
|
||||
on<UpdateLockEvent>(_updateLock);
|
||||
on<DoorLockFactoryReset>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus =
|
||||
DoorLockStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<DoorLockState> emit) {
|
||||
emit(DoorLockStatusLoading());
|
||||
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(DoorLockStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
FutureOr<void> _onFetchDeviceStatus(
|
||||
@ -28,6 +62,8 @@ class DoorLockBloc extends Bloc<DoorLockEvent, DoorLockState> {
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus =
|
||||
DoorLockStatusModel.fromJson(event.deviceId, status.status);
|
||||
_listenToChanges(event.deviceId);
|
||||
|
||||
emit(DoorLockStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(DoorLockControlError(e.toString()));
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/door_lock/models/door_lock_status_model.dart';
|
||||
|
||||
sealed class DoorLockEvent extends Equatable {
|
||||
const DoorLockEvent();
|
||||
@ -51,3 +52,10 @@ class DoorLockFactoryReset extends DoorLockEvent {
|
||||
@override
|
||||
List<Object> get props => [deviceId, factoryReset];
|
||||
}
|
||||
|
||||
class StatusUpdated extends DoorLockEvent {
|
||||
final DoorLockStatusModel deviceStatus;
|
||||
const StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/garage_door/bloc/garage_door_event.dart';
|
||||
@ -39,31 +40,68 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
on<GarageDoorFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||
on<GarageDoorFactoryResetEvent>(_onFactoryReset);
|
||||
on<EditGarageDoorScheduleEvent>(_onEditSchedule);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus =
|
||||
GarageDoorStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _fetchGarageDoorStatus(GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<GarageDoorState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
}
|
||||
|
||||
void _fetchGarageDoorStatus(
|
||||
GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
|
||||
emit(GarageDoorLoadingState());
|
||||
try {
|
||||
var response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
var response =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status);
|
||||
_listenToChanges(deviceId);
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
} catch (e) {
|
||||
emit(GarageDoorErrorState(message: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event,
|
||||
Emitter<GarageDoorState> emit) async {
|
||||
emit(GarageDoorLoadingState());
|
||||
try {
|
||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||
deviceStatus = GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
|
||||
final status =
|
||||
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||
deviceStatus =
|
||||
GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
|
||||
emit(GarageDoorBatchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(GarageDoorBatchControlError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _addSchedule(AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _addSchedule(
|
||||
AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
try {
|
||||
ScheduleEntry newSchedule = ScheduleEntry(
|
||||
category: event.category,
|
||||
@ -71,9 +109,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
function: Status(code: 'switch_1', value: event.functionOn),
|
||||
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
||||
);
|
||||
bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
|
||||
bool success =
|
||||
await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
|
||||
if (success) {
|
||||
add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
|
||||
add(FetchGarageDoorSchedulesEvent(
|
||||
deviceId: deviceId, category: 'switch_1'));
|
||||
} else {
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
}
|
||||
@ -82,16 +122,19 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateCountdownAlarm(UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
|
||||
void _onUpdateCountdownAlarm(
|
||||
UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
|
||||
final currentState = state;
|
||||
if (currentState is GarageDoorLoadedState) {
|
||||
emit(currentState.copyWith(
|
||||
status: currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
|
||||
status:
|
||||
currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _onUpdateTrTimeCon(UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
|
||||
void _onUpdateTrTimeCon(
|
||||
UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
|
||||
final currentState = state;
|
||||
if (currentState is GarageDoorLoadedState) {
|
||||
emit(currentState.copyWith(
|
||||
@ -100,7 +143,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event,
|
||||
Emitter<GarageDoorState> emit) async {
|
||||
try {
|
||||
final updatedSchedules = deviceStatus.schedules?.map((schedule) {
|
||||
if (schedule.scheduleId == event.scheduleId) {
|
||||
@ -127,12 +171,15 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event,
|
||||
Emitter<GarageDoorState> emit) async {
|
||||
try {
|
||||
bool success = await DevicesManagementApi().deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
|
||||
bool success = await DevicesManagementApi()
|
||||
.deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
|
||||
if (success) {
|
||||
final updatedSchedules =
|
||||
deviceStatus.schedules?.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
|
||||
final updatedSchedules = deviceStatus.schedules
|
||||
?.where((schedule) => schedule.scheduleId != event.scheduleId)
|
||||
.toList();
|
||||
deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules);
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
} else {
|
||||
@ -143,11 +190,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event,
|
||||
Emitter<GarageDoorState> emit) async {
|
||||
emit(ScheduleGarageLoadingState());
|
||||
try {
|
||||
List<ScheduleModel> schedules =
|
||||
await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
|
||||
List<ScheduleModel> schedules = await DevicesManagementApi()
|
||||
.getDeviceSchedules(deviceStatus.uuid, event.category);
|
||||
deviceStatus = deviceStatus.copyWith(schedules: schedules);
|
||||
emit(
|
||||
GarageDoorLoadedState(
|
||||
@ -165,30 +213,37 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateSelectedTime(UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _updateSelectedTime(
|
||||
UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
|
||||
final currentState = state;
|
||||
if (currentState is GarageDoorLoadedState) {
|
||||
emit(currentState.copyWith(selectedTime: event.selectedTime));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateSelectedDay(UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _updateSelectedDay(
|
||||
UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
|
||||
final currentState = state;
|
||||
if (currentState is GarageDoorLoadedState) {
|
||||
List<bool> updatedDays = List.from(currentState.selectedDays);
|
||||
updatedDays[event.dayIndex] = event.isSelected;
|
||||
emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
||||
emit(currentState.copyWith(
|
||||
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateFunctionOn(UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _updateFunctionOn(
|
||||
UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
|
||||
final currentState = state;
|
||||
if (currentState is GarageDoorLoadedState) {
|
||||
emit(currentState.copyWith(functionOn: event.functionOn, selectedTime: currentState.selectedTime));
|
||||
emit(currentState.copyWith(
|
||||
functionOn: event.functionOn,
|
||||
selectedTime: currentState.selectedTime));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initializeAddSchedule(InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _initializeAddSchedule(
|
||||
InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
final currentState = state;
|
||||
if (currentState is GarageDoorLoadedState) {
|
||||
emit(currentState.copyWith(
|
||||
@ -200,20 +255,25 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _fetchRecords(FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _fetchRecords(
|
||||
FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
|
||||
emit(GarageDoorReportsLoadingState());
|
||||
try {
|
||||
final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
|
||||
final from = DateTime.now()
|
||||
.subtract(const Duration(days: 30))
|
||||
.millisecondsSinceEpoch;
|
||||
final to = DateTime.now().millisecondsSinceEpoch;
|
||||
final DeviceReport records =
|
||||
await DevicesManagementApi.getDeviceReportsByDate(event.deviceId, 'switch_1', from.toString(), to.toString());
|
||||
await DevicesManagementApi.getDeviceReportsByDate(
|
||||
event.deviceId, 'switch_1', from.toString(), to.toString());
|
||||
emit(GarageDoorReportsState(deviceReport: records));
|
||||
} catch (e) {
|
||||
emit(GarageDoorReportsFailedState(error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onBatchControl(GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _onBatchControl(
|
||||
GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
|
||||
final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false;
|
||||
|
||||
_updateLocalValue(event.code, event.value);
|
||||
@ -233,11 +293,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _backToGridView(BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
|
||||
void _backToGridView(
|
||||
BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
}
|
||||
|
||||
void _handleUpdate(GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
|
||||
void _handleUpdate(
|
||||
GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
}
|
||||
|
||||
@ -253,9 +315,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
late bool status;
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
if (isBatch) {
|
||||
status = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
||||
status = await DevicesManagementApi()
|
||||
.deviceBatchControl(deviceId, code, value);
|
||||
} else {
|
||||
status = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
|
||||
status = await DevicesManagementApi()
|
||||
.deviceControl(deviceId, Status(code: code, value: value));
|
||||
}
|
||||
|
||||
if (!status) {
|
||||
@ -270,10 +334,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onFactoryReset(GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
|
||||
Future<void> _onFactoryReset(
|
||||
GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
|
||||
emit(GarageDoorLoadingState());
|
||||
try {
|
||||
final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
|
||||
final response = await DevicesManagementApi()
|
||||
.factoryReset(event.factoryReset, event.deviceId);
|
||||
if (!response) {
|
||||
emit(const GarageDoorErrorState(message: 'Failed to reset device'));
|
||||
} else {
|
||||
@ -284,34 +350,47 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _increaseDelay(IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
||||
void _increaseDelay(
|
||||
IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
||||
// if (deviceStatus.countdown1 != 0) {
|
||||
try {
|
||||
deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay + Duration(minutes: 10));
|
||||
deviceStatus = deviceStatus.copyWith(
|
||||
delay: deviceStatus.delay + Duration(minutes: 10));
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
|
||||
add(GarageDoorControlEvent(
|
||||
deviceId: event.deviceId,
|
||||
value: deviceStatus.delay.inSeconds,
|
||||
code: 'countdown_1'));
|
||||
} catch (e) {
|
||||
emit(GarageDoorErrorState(message: e.toString()));
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void _decreaseDelay(DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
||||
void _decreaseDelay(
|
||||
DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
|
||||
// if (deviceStatus.countdown1 != 0) {
|
||||
try {
|
||||
if (deviceStatus.delay.inMinutes > 10) {
|
||||
deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay - Duration(minutes: 10));
|
||||
deviceStatus = deviceStatus.copyWith(
|
||||
delay: deviceStatus.delay - Duration(minutes: 10));
|
||||
}
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
|
||||
add(GarageDoorControlEvent(
|
||||
deviceId: event.deviceId,
|
||||
value: deviceStatus.delay.inSeconds,
|
||||
code: 'countdown_1'));
|
||||
} catch (e) {
|
||||
emit(GarageDoorErrorState(message: e.toString()));
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
void _garageDoorControlEvent(GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async {
|
||||
final oldValue = event.code == 'countdown_1' ? deviceStatus.countdown1 : deviceStatus.switch1;
|
||||
void _garageDoorControlEvent(
|
||||
GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async {
|
||||
final oldValue = event.code == 'countdown_1'
|
||||
? deviceStatus.countdown1
|
||||
: deviceStatus.switch1;
|
||||
_updateLocalValue(event.code, event.value);
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
final success = await _runDeBouncer(
|
||||
@ -327,7 +406,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _revertValue(String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
|
||||
void _revertValue(
|
||||
String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
|
||||
switch (code) {
|
||||
case 'switch_1':
|
||||
if (oldValue is bool) {
|
||||
@ -336,7 +416,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
break;
|
||||
case 'countdown_1':
|
||||
if (oldValue is int) {
|
||||
deviceStatus = deviceStatus.copyWith(countdown1: oldValue, delay: Duration(seconds: oldValue));
|
||||
deviceStatus = deviceStatus.copyWith(
|
||||
countdown1: oldValue, delay: Duration(seconds: oldValue));
|
||||
}
|
||||
break;
|
||||
// Add other cases if needed
|
||||
@ -358,7 +439,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
break;
|
||||
case 'countdown_1':
|
||||
if (value is int) {
|
||||
deviceStatus = deviceStatus.copyWith(countdown1: value, delay: Duration(seconds: value));
|
||||
deviceStatus = deviceStatus.copyWith(
|
||||
countdown1: value, delay: Duration(seconds: value));
|
||||
}
|
||||
break;
|
||||
case 'countdown_alarm':
|
||||
@ -401,7 +483,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
FutureOr<void> _onEditSchedule(EditGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
FutureOr<void> _onEditSchedule(
|
||||
EditGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
|
||||
try {
|
||||
ScheduleEntry newSchedule = ScheduleEntry(
|
||||
scheduleId: event.scheduleId,
|
||||
@ -410,9 +493,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
|
||||
function: Status(code: 'switch_1', value: event.functionOn),
|
||||
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
|
||||
);
|
||||
bool success = await DevicesManagementApi().editScheduleRecord(deviceId, newSchedule);
|
||||
bool success = await DevicesManagementApi()
|
||||
.editScheduleRecord(deviceId, newSchedule);
|
||||
if (success) {
|
||||
add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
|
||||
add(FetchGarageDoorSchedulesEvent(
|
||||
deviceId: deviceId, category: 'switch_1'));
|
||||
} else {
|
||||
emit(GarageDoorLoadedState(status: deviceStatus));
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/garage_door/models/garage_door_model.dart';
|
||||
|
||||
abstract class GarageDoorEvent extends Equatable {
|
||||
const GarageDoorEvent();
|
||||
@ -25,7 +26,8 @@ class GarageDoorControlEvent extends GarageDoorEvent {
|
||||
final dynamic value;
|
||||
final String code;
|
||||
|
||||
const GarageDoorControlEvent({required this.deviceId, required this.value, required this.code});
|
||||
const GarageDoorControlEvent(
|
||||
{required this.deviceId, required this.value, required this.code});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [deviceId, value];
|
||||
@ -121,7 +123,8 @@ class FetchGarageDoorRecordsEvent extends GarageDoorEvent {
|
||||
final String deviceId;
|
||||
final String code;
|
||||
|
||||
const FetchGarageDoorRecordsEvent({required this.deviceId, required this.code});
|
||||
const FetchGarageDoorRecordsEvent(
|
||||
{required this.deviceId, required this.code});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [deviceId, code];
|
||||
@ -232,3 +235,10 @@ class GarageDoorFactoryResetEvent extends GarageDoorEvent {
|
||||
@override
|
||||
List<Object?> get props => [factoryReset, deviceId];
|
||||
}
|
||||
|
||||
class StatusUpdated extends GarageDoorEvent {
|
||||
final GarageDoorStatusModel deviceStatus;
|
||||
const StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
@ -16,6 +17,7 @@ class MainDoorSensorBloc
|
||||
on<MainDoorSensorFetchBatchEvent>(_onFetchBatchStatus);
|
||||
on<MainDoorSensorReportsEvent>(_fetchReports);
|
||||
on<MainDoorSensorFactoryReset>(_factoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
late MainDoorSensorStatusModel deviceStatus;
|
||||
@ -28,7 +30,7 @@ class MainDoorSensorBloc
|
||||
final status = await DevicesManagementApi()
|
||||
.getDeviceStatus(event.deviceId)
|
||||
.then((value) => value.status);
|
||||
|
||||
_listenToChanges(event.deviceId);
|
||||
deviceStatus = MainDoorSensorStatusModel.fromJson(event.deviceId, status);
|
||||
emit(MainDoorSensorDeviceStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
@ -156,4 +158,35 @@ class MainDoorSensorBloc
|
||||
emit(MainDoorSensorFailedState(error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus = MainDoorSensorStatusModel.fromJson(
|
||||
usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(
|
||||
StatusUpdated event, Emitter<MainDoorSensorState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(MainDoorSensorDeviceStatusLoaded(deviceStatus));
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/main_door_sensor/models/main_door_status_model.dart';
|
||||
|
||||
import '../../all_devices/models/factory_reset_model.dart';
|
||||
|
||||
@ -71,3 +72,10 @@ class MainDoorSensorFactoryReset extends MainDoorSensorEvent {
|
||||
MainDoorSensorFactoryReset(
|
||||
{required this.deviceId, required this.factoryReset});
|
||||
}
|
||||
|
||||
class StatusUpdated extends MainDoorSensorEvent {
|
||||
final MainDoorSensorStatusModel deviceStatus;
|
||||
StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
@ -10,33 +11,71 @@ import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
part 'one_gang_glass_switch_event.dart';
|
||||
part 'one_gang_glass_switch_state.dart';
|
||||
|
||||
class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
|
||||
class OneGangGlassSwitchBloc
|
||||
extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
|
||||
OneGangGlassStatusModel deviceStatus;
|
||||
Timer? _timer;
|
||||
|
||||
OneGangGlassSwitchBloc({required String deviceId})
|
||||
: deviceStatus = OneGangGlassStatusModel(uuid: deviceId, switch1: false, countDown: 0),
|
||||
: deviceStatus = OneGangGlassStatusModel(
|
||||
uuid: deviceId, switch1: false, countDown: 0),
|
||||
super(OneGangGlassSwitchInitial()) {
|
||||
on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||
on<OneGangGlassSwitchControl>(_onControl);
|
||||
on<OneGangGlassSwitchBatchControl>(_onBatchControl);
|
||||
on<OneGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||
on<OneGangGlassFactoryResetEvent>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
Future<void> _onFetchDeviceStatus(
|
||||
OneGangGlassSwitchFetchDeviceEvent event, Emitter<OneGangGlassSwitchState> emit) async {
|
||||
Future<void> _onFetchDeviceStatus(OneGangGlassSwitchFetchDeviceEvent event,
|
||||
Emitter<OneGangGlassSwitchState> emit) async {
|
||||
emit(OneGangGlassSwitchLoading());
|
||||
try {
|
||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
_listenToChanges(event.deviceId);
|
||||
deviceStatus =
|
||||
OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(OneGangGlassSwitchError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onControl(OneGangGlassSwitchControl event, Emitter<OneGangGlassSwitchState> emit) async {
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus = OneGangGlassStatusModel.fromJson(
|
||||
usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(
|
||||
StatusUpdated event, Emitter<OneGangGlassSwitchState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
Future<void> _onControl(OneGangGlassSwitchControl event,
|
||||
Emitter<OneGangGlassSwitchState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
||||
_updateLocalValue(event.code, event.value);
|
||||
@ -52,10 +91,12 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event, Emitter<OneGangGlassSwitchState> emit) async {
|
||||
Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event,
|
||||
Emitter<OneGangGlassSwitchState> emit) async {
|
||||
emit(OneGangGlassSwitchLoading());
|
||||
try {
|
||||
final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
|
||||
final response = await DevicesManagementApi()
|
||||
.factoryReset(event.factoryReset, event.deviceId);
|
||||
if (!response) {
|
||||
emit(OneGangGlassSwitchError('Failed to reset device'));
|
||||
} else {
|
||||
@ -66,7 +107,8 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event, Emitter<OneGangGlassSwitchState> emit) async {
|
||||
Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event,
|
||||
Emitter<OneGangGlassSwitchState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
||||
_updateLocalValue(event.code, event.value);
|
||||
@ -83,11 +125,14 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
||||
}
|
||||
|
||||
Future<void> _onFetchBatchStatus(
|
||||
OneGangGlassSwitchFetchBatchStatusEvent event, Emitter<OneGangGlassSwitchState> emit) async {
|
||||
OneGangGlassSwitchFetchBatchStatusEvent event,
|
||||
Emitter<OneGangGlassSwitchState> emit) async {
|
||||
emit(OneGangGlassSwitchLoading());
|
||||
try {
|
||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
|
||||
final status =
|
||||
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||
deviceStatus = OneGangGlassStatusModel.fromJson(
|
||||
event.deviceIds.first, status.status);
|
||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(OneGangGlassSwitchError(e.toString()));
|
||||
@ -117,9 +162,11 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
||||
try {
|
||||
late bool response;
|
||||
if (isBatch) {
|
||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
||||
response = await DevicesManagementApi()
|
||||
.deviceBatchControl(deviceId, code, value);
|
||||
} else {
|
||||
response = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
|
||||
response = await DevicesManagementApi()
|
||||
.deviceControl(deviceId, Status(code: code, value: value));
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
@ -131,7 +178,8 @@ class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassS
|
||||
});
|
||||
}
|
||||
|
||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue, Emitter<OneGangGlassSwitchState> emit) {
|
||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
||||
Emitter<OneGangGlassSwitchState> emit) {
|
||||
_updateLocalValue(code, oldValue);
|
||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
@ -39,6 +39,11 @@ class OneGangGlassSwitchFetchBatchStatusEvent extends OneGangGlassSwitchEvent {
|
||||
OneGangGlassSwitchFetchBatchStatusEvent(this.deviceIds);
|
||||
}
|
||||
|
||||
class StatusUpdated extends OneGangGlassSwitchEvent {
|
||||
final OneGangGlassStatusModel deviceStatus;
|
||||
StatusUpdated(this.deviceStatus);
|
||||
}
|
||||
|
||||
class OneGangGlassFactoryResetEvent extends OneGangGlassSwitchEvent {
|
||||
final FactoryResetModel factoryReset;
|
||||
final String deviceId;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart';
|
||||
@ -16,6 +17,7 @@ class WallLightSwitchBloc
|
||||
on<WallLightSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
||||
on<WallLightSwitchBatchControl>(_onBatchControl);
|
||||
on<WallLightFactoryReset>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
late WallLightStatusModel deviceStatus;
|
||||
@ -31,12 +33,44 @@ class WallLightSwitchBloc
|
||||
|
||||
deviceStatus =
|
||||
WallLightStatusModel.fromJson(event.deviceId, status.status);
|
||||
_listenToChanges(event.deviceId);
|
||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(WallLightSwitchError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus =
|
||||
WallLightStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(
|
||||
StatusUpdated event, Emitter<WallLightSwitchState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(WallLightSwitchStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
FutureOr<void> _onControl(
|
||||
WallLightSwitchControl event, Emitter<WallLightSwitchState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/models/wall_light_status_model.dart';
|
||||
|
||||
class WallLightSwitchEvent extends Equatable {
|
||||
@override
|
||||
@ -57,3 +58,10 @@ class WallLightFactoryReset extends WallLightSwitchEvent {
|
||||
@override
|
||||
List<Object> get props => [deviceId, factoryReset];
|
||||
}
|
||||
|
||||
class StatusUpdated extends WallLightSwitchEvent {
|
||||
final WallLightStatusModel deviceStatus;
|
||||
StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
@ -10,7 +11,8 @@ import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
part 'three_gang_glass_switch_event.dart';
|
||||
part 'three_gang_glass_switch_state.dart';
|
||||
|
||||
class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> {
|
||||
class ThreeGangGlassSwitchBloc
|
||||
extends Bloc<ThreeGangGlassSwitchEvent, ThreeGangGlassSwitchState> {
|
||||
ThreeGangGlassStatusModel deviceStatus;
|
||||
Timer? _timer;
|
||||
|
||||
@ -29,21 +31,57 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
||||
on<ThreeGangGlassSwitchBatchControl>(_onBatchControl);
|
||||
on<ThreeGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||
on<ThreeGangGlassFactoryReset>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
Future<void> _onFetchDeviceStatus(
|
||||
ThreeGangGlassSwitchFetchDeviceEvent event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
Future<void> _onFetchDeviceStatus(ThreeGangGlassSwitchFetchDeviceEvent event,
|
||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
emit(ThreeGangGlassSwitchLoading());
|
||||
try {
|
||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus =
|
||||
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||
_listenToChanges(event.deviceId);
|
||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onControl(ThreeGangGlassSwitchControl event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(
|
||||
usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(
|
||||
StatusUpdated event, Emitter<ThreeGangGlassSwitchState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
Future<void> _onControl(ThreeGangGlassSwitchControl event,
|
||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
||||
_updateLocalValue(event.code, event.value);
|
||||
@ -59,7 +97,8 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onBatchControl(ThreeGangGlassSwitchBatchControl event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
Future<void> _onBatchControl(ThreeGangGlassSwitchBatchControl event,
|
||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
||||
_updateLocalValue(event.code, event.value);
|
||||
@ -76,21 +115,26 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
||||
}
|
||||
|
||||
Future<void> _onFetchBatchStatus(
|
||||
ThreeGangGlassSwitchFetchBatchStatusEvent event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
ThreeGangGlassSwitchFetchBatchStatusEvent event,
|
||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
emit(ThreeGangGlassSwitchLoading());
|
||||
try {
|
||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
|
||||
final status =
|
||||
await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||
deviceStatus = ThreeGangGlassStatusModel.fromJson(
|
||||
event.deviceIds.first, status.status);
|
||||
emit(ThreeGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(ThreeGangGlassSwitchError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onFactoryReset(ThreeGangGlassFactoryReset event, Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
Future<void> _onFactoryReset(ThreeGangGlassFactoryReset event,
|
||||
Emitter<ThreeGangGlassSwitchState> emit) async {
|
||||
emit(ThreeGangGlassSwitchLoading());
|
||||
try {
|
||||
final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
|
||||
final response = await DevicesManagementApi()
|
||||
.factoryReset(event.factoryReset, event.deviceId);
|
||||
if (!response) {
|
||||
emit(ThreeGangGlassSwitchError('Failed'));
|
||||
} else {
|
||||
@ -124,9 +168,11 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
||||
try {
|
||||
late bool response;
|
||||
if (isBatch) {
|
||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
||||
response = await DevicesManagementApi()
|
||||
.deviceBatchControl(deviceId, code, value);
|
||||
} else {
|
||||
response = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
|
||||
response = await DevicesManagementApi()
|
||||
.deviceControl(deviceId, Status(code: code, value: value));
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
@ -138,7 +184,8 @@ class ThreeGangGlassSwitchBloc extends Bloc<ThreeGangGlassSwitchEvent, ThreeGang
|
||||
});
|
||||
}
|
||||
|
||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue, Emitter<ThreeGangGlassSwitchState> emit) {
|
||||
void _revertValueAndEmit(String deviceId, String code, bool oldValue,
|
||||
Emitter<ThreeGangGlassSwitchState> emit) {
|
||||
_updateLocalValue(code, oldValue);
|
||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
@ -49,3 +49,10 @@ class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent {
|
||||
required this.factoryReset,
|
||||
});
|
||||
}
|
||||
|
||||
class StatusUpdated extends ThreeGangGlassSwitchEvent {
|
||||
final ThreeGangGlassStatusModel deviceStatus;
|
||||
StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart';
|
||||
@ -22,6 +23,7 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
||||
on<LivingRoomBatchControl>(_livingRoomBatchControl);
|
||||
on<LivingRoomFetchBatchEvent>(_livingRoomFetchBatchControl);
|
||||
on<LivingRoomFactoryResetEvent>(_livingRoomFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
FutureOr<void> _onFetchDeviceStatus(LivingRoomFetchDeviceStatusEvent event,
|
||||
@ -32,6 +34,7 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus =
|
||||
LivingRoomStatusModel.fromJson(event.deviceId, status.status);
|
||||
_listenToChanges(deviceId);
|
||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||
@ -144,6 +147,9 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||
deviceStatus =
|
||||
LivingRoomStatusModel.fromJson(event.devicesIds.first, status.status);
|
||||
// for (var deviceId in event.devicesIds) {
|
||||
// _listenToChanges(deviceId);
|
||||
// }
|
||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||
@ -185,4 +191,34 @@ class LivingRoomBloc extends Bloc<LivingRoomEvent, LivingRoomState> {
|
||||
emit(LivingRoomDeviceManagementError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus =
|
||||
LivingRoomStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<LivingRoomState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(LivingRoomDeviceStatusLoaded(deviceStatus));
|
||||
}
|
||||
}
|
||||
|
@ -58,3 +58,10 @@ class LivingRoomFactoryResetEvent extends LivingRoomEvent {
|
||||
@override
|
||||
List<Object> get props => [uuid, factoryReset];
|
||||
}
|
||||
|
||||
class StatusUpdated extends LivingRoomEvent {
|
||||
final LivingRoomStatusModel deviceStatus;
|
||||
const StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
|
||||
part 'two_gang_glass_switch_event.dart';
|
||||
part 'two_gang_glass_switch_state.dart';
|
||||
|
||||
@ -14,7 +13,6 @@ class TwoGangGlassSwitchBloc
|
||||
extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
|
||||
TwoGangGlassStatusModel deviceStatus;
|
||||
Timer? _timer;
|
||||
|
||||
TwoGangGlassSwitchBloc({required String deviceId})
|
||||
: deviceStatus = TwoGangGlassStatusModel(
|
||||
uuid: deviceId,
|
||||
@ -28,6 +26,7 @@ class TwoGangGlassSwitchBloc
|
||||
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
||||
on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||
on<TwoGangGlassFactoryReset>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
Future<void> _onFetchDeviceStatus(TwoGangGlassSwitchFetchDeviceEvent event,
|
||||
@ -38,12 +37,44 @@ class TwoGangGlassSwitchBloc
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus =
|
||||
TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||
_listenToChanges(event.deviceId);
|
||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(TwoGangGlassSwitchError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _listenToChanges(String deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
ref.onValue.listen((DatabaseEvent event) {
|
||||
if (event.snapshot.value == null) return;
|
||||
|
||||
Map<dynamic, dynamic> data =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
List<Status> statusList = [];
|
||||
|
||||
data['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
// Parse the new status and add the event
|
||||
final updatedStatus =
|
||||
TwoGangGlassStatusModel.fromJson(data['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(updatedStatus));
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// Handle errors and emit an error state if necessary
|
||||
if (!isClosed) {
|
||||
// add(TwoGangGlassSwitchError('Error listening to updates: $e'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onControl(TwoGangGlassSwitchControl event,
|
||||
Emitter<TwoGangGlassSwitchState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
@ -178,4 +209,37 @@ class TwoGangGlassSwitchBloc
|
||||
_timer?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
// _listenToChanges(deviceId) {
|
||||
// try {
|
||||
// DatabaseReference ref =
|
||||
// FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
// Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
// stream.listen((DatabaseEvent event) {
|
||||
// Map<dynamic, dynamic> usersMap =
|
||||
// event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
// List<Status> statusList = [];
|
||||
// usersMap['status'].forEach((element) {
|
||||
// statusList
|
||||
// .add(Status(code: element['code'], value: element['value']));
|
||||
// });
|
||||
|
||||
// deviceStatus = TwoGangGlassStatusModel.fromJson(
|
||||
// usersMap['productUuid'], statusList);
|
||||
// if (!isClosed) {
|
||||
// add(StatusUpdated(deviceStatus));
|
||||
// }
|
||||
// });
|
||||
// } catch (_) {}
|
||||
// }
|
||||
|
||||
void _onStatusUpdated(
|
||||
StatusUpdated event, Emitter<TwoGangGlassSwitchState> emit) {
|
||||
// Update the local deviceStatus with the new status from the event
|
||||
deviceStatus = event.deviceStatus;
|
||||
// Emit the new state with the updated status
|
||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||
}
|
||||
}
|
||||
|
@ -48,3 +48,11 @@ class TwoGangGlassFactoryReset extends TwoGangGlassSwitchEvent {
|
||||
required this.factoryReset,
|
||||
});
|
||||
}
|
||||
|
||||
class StatusUpdated extends TwoGangGlassSwitchEvent {
|
||||
final TwoGangGlassStatusModel deviceStatus;
|
||||
StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,8 @@ import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class TwoGangGlassSwitchControlView extends StatelessWidget with HelperResponsiveLayout {
|
||||
class TwoGangGlassSwitchControlView extends StatelessWidget
|
||||
with HelperResponsiveLayout {
|
||||
final String deviceId;
|
||||
|
||||
const TwoGangGlassSwitchControlView({required this.deviceId, super.key});
|
||||
@ -14,25 +15,25 @@ class TwoGangGlassSwitchControlView extends StatelessWidget with HelperResponsiv
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) =>
|
||||
TwoGangGlassSwitchBloc(deviceId: deviceId)..add(TwoGangGlassSwitchFetchDeviceEvent(deviceId)),
|
||||
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
||||
builder: (context, state) {
|
||||
if (state is TwoGangGlassSwitchLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is TwoGangGlassSwitchStatusLoaded) {
|
||||
return _buildStatusControls(context, state.status);
|
||||
} else if (state is TwoGangGlassSwitchError) {
|
||||
return const Center(child: Text('Error fetching status'));
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
create: (context) => TwoGangGlassSwitchBloc(deviceId: deviceId)
|
||||
..add(TwoGangGlassSwitchFetchDeviceEvent(deviceId)),
|
||||
child: BlocBuilder<TwoGangGlassSwitchBloc, TwoGangGlassSwitchState>(
|
||||
builder: (context, state) {
|
||||
if (state is TwoGangGlassSwitchLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is TwoGangGlassSwitchStatusLoaded) {
|
||||
return _buildStatusControls(context, state.status);
|
||||
} else if (state is TwoGangGlassSwitchError) {
|
||||
return Center(child: Text(state.message));
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildStatusControls(BuildContext context, TwoGangGlassStatusModel status) {
|
||||
Widget _buildStatusControls(
|
||||
BuildContext context, TwoGangGlassStatusModel status) {
|
||||
final isExtraLarge = isExtraLargeScreenSize(context);
|
||||
final isLarge = isLargeScreenSize(context);
|
||||
final isMedium = isMediumScreenSize(context);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart';
|
||||
@ -14,6 +15,7 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
||||
on<TwoGangSwitchFetchBatchEvent>(_onFetchBatchStatus);
|
||||
on<TwoGangSwitchBatchControl>(_onBatchControl);
|
||||
on<TwoGangFactoryReset>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
late TwoGangStatusModel deviceStatus;
|
||||
@ -26,8 +28,8 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
||||
try {
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
|
||||
deviceStatus = TwoGangStatusModel.fromJson(event.deviceId, status.status);
|
||||
_listenToChanges(emit);
|
||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(TwoGangSwitchError(e.toString()));
|
||||
@ -174,4 +176,34 @@ class TwoGangSwitchBloc extends Bloc<TwoGangSwitchEvent, TwoGangSwitchState> {
|
||||
emit(TwoGangSwitchError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus =
|
||||
TwoGangStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<TwoGangSwitchState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(TwoGangSwitchStatusLoaded(deviceStatus));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/models/two_gang_status_model.dart';
|
||||
|
||||
class TwoGangSwitchEvent extends Equatable {
|
||||
@override
|
||||
@ -57,3 +58,10 @@ class TwoGangFactoryReset extends TwoGangSwitchEvent {
|
||||
@override
|
||||
List<Object> get props => [deviceId, factoryReset];
|
||||
}
|
||||
|
||||
class StatusUpdated extends TwoGangSwitchEvent {
|
||||
final TwoGangStatusModel deviceStatus;
|
||||
StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
|
||||
@ -29,7 +30,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
||||
var response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
||||
deviceStatus = WallSensorModel.fromJson(response.status);
|
||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||
// _listenToChanges();
|
||||
_listenToChanges(emit);
|
||||
} catch (e) {
|
||||
emit(WallSensorFailedState(error: e.toString()));
|
||||
return;
|
||||
@ -38,10 +39,12 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
||||
|
||||
// Fetch batch status
|
||||
FutureOr<void> _fetchWallSensorBatchControl(
|
||||
WallSensorFetchBatchStatusEvent event, Emitter<WallSensorState> emit) async {
|
||||
WallSensorFetchBatchStatusEvent event,
|
||||
Emitter<WallSensorState> emit) async {
|
||||
emit(WallSensorLoadingInitialState());
|
||||
try {
|
||||
var response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||
var response =
|
||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||
deviceStatus = WallSensorModel.fromJson(response.status);
|
||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||
} catch (e) {
|
||||
@ -49,26 +52,30 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
// _listenToChanges() {
|
||||
// try {
|
||||
// DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
// Stream<DatabaseEvent> stream = ref.onValue;
|
||||
_listenToChanges(Emitter<WallSensorState> emit) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
// stream.listen((DatabaseEvent event) {
|
||||
// Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||
// List<StatusModel> statusList = [];
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
List<Status> statusList = [];
|
||||
|
||||
// usersMap['status'].forEach((element) {
|
||||
// statusList.add(StatusModel(code: element['code'], value: element['value']));
|
||||
// });
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
// deviceStatus = WallSensorModel.fromJson(statusList);
|
||||
// add(WallSensorUpdatedEvent());
|
||||
// });
|
||||
// } catch (_) {}
|
||||
// }
|
||||
deviceStatus = WallSensorModel.fromJson(statusList);
|
||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _changeValue(WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
|
||||
void _changeValue(
|
||||
WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
|
||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||
if (event.code == 'far_detection') {
|
||||
deviceStatus.farDetection = event.value;
|
||||
@ -125,7 +132,8 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
||||
try {
|
||||
late bool response;
|
||||
if (isBatch) {
|
||||
response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
|
||||
response = await DevicesManagementApi()
|
||||
.deviceBatchControl(deviceId, code, value);
|
||||
} else {
|
||||
response = await DevicesManagementApi()
|
||||
.deviceControl(deviceId, Status(code: code, value: value));
|
||||
@ -150,7 +158,8 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
||||
try {
|
||||
// await DevicesManagementApi.getDeviceReportsByDate(
|
||||
// deviceId, event.code, from.toString(), to.toString())
|
||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code).then((value) {
|
||||
await DevicesManagementApi.getDeviceReports(deviceId, event.code)
|
||||
.then((value) {
|
||||
emit(DeviceReportsState(deviceReport: value, code: event.code));
|
||||
});
|
||||
} catch (e) {
|
||||
@ -159,11 +168,13 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _showDescription(ShowDescriptionEvent event, Emitter<WallSensorState> emit) {
|
||||
void _showDescription(
|
||||
ShowDescriptionEvent event, Emitter<WallSensorState> emit) {
|
||||
emit(WallSensorShowDescriptionState(description: event.description));
|
||||
}
|
||||
|
||||
void _backToGridView(BackToGridViewEvent event, Emitter<WallSensorState> emit) {
|
||||
void _backToGridView(
|
||||
BackToGridViewEvent event, Emitter<WallSensorState> emit) {
|
||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.dart';
|
||||
@ -34,6 +35,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
on<EditWaterHeaterScheduleEvent>(_onEditSchedule);
|
||||
on<DeleteScheduleEvent>(_onDeleteSchedule);
|
||||
on<UpdateScheduleEntryEvent>(_onUpdateSchedule);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
late WaterHeaterStatusModel deviceStatus;
|
||||
@ -78,7 +80,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||
final updatedDays = List<bool>.from(currentState.selectedDays);
|
||||
updatedDays[event.index] = event.value;
|
||||
emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
||||
emit(currentState.copyWith(
|
||||
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
|
||||
}
|
||||
|
||||
FutureOr<void> _updateFunctionOn(
|
||||
@ -86,7 +89,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
Emitter<WaterHeaterState> emit,
|
||||
) {
|
||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||
emit(currentState.copyWith(functionOn: event.isOn, selectedTime: currentState.selectedTime));
|
||||
emit(currentState.copyWith(
|
||||
functionOn: event.isOn, selectedTime: currentState.selectedTime));
|
||||
}
|
||||
|
||||
FutureOr<void> _updateScheduleEvent(
|
||||
@ -101,7 +105,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
));
|
||||
}
|
||||
if (event.scheduleMode == ScheduleModes.countdown) {
|
||||
final countdownRemaining = Duration(hours: event.hours, minutes: event.minutes);
|
||||
final countdownRemaining =
|
||||
Duration(hours: event.hours, minutes: event.minutes);
|
||||
|
||||
emit(currentState.copyWith(
|
||||
scheduleMode: ScheduleModes.countdown,
|
||||
@ -111,11 +116,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
countdownRemaining: countdownRemaining,
|
||||
));
|
||||
|
||||
if (!currentState.isCountdownActive! && countdownRemaining > Duration.zero) {
|
||||
if (!currentState.isCountdownActive! &&
|
||||
countdownRemaining > Duration.zero) {
|
||||
_startCountdownTimer(emit, countdownRemaining);
|
||||
}
|
||||
} else if (event.scheduleMode == ScheduleModes.inching) {
|
||||
final inchingDuration = Duration(hours: event.hours, minutes: event.minutes);
|
||||
final inchingDuration =
|
||||
Duration(hours: event.hours, minutes: event.minutes);
|
||||
|
||||
emit(currentState.copyWith(
|
||||
scheduleMode: ScheduleModes.inching,
|
||||
@ -217,7 +224,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
try {
|
||||
final status = await DevicesManagementApi().deviceControl(
|
||||
event.deviceId,
|
||||
Status(code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
|
||||
Status(
|
||||
code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
|
||||
);
|
||||
if (!status) {
|
||||
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
|
||||
@ -235,8 +243,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
emit(WaterHeaterLoadingState());
|
||||
|
||||
try {
|
||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus =
|
||||
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||
|
||||
if (deviceStatus.scheduleMode == ScheduleModes.countdown) {
|
||||
final countdownRemaining = Duration(
|
||||
@ -300,11 +310,42 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
isInchingActive: false,
|
||||
));
|
||||
}
|
||||
_listenToChanges(event.deviceId);
|
||||
} catch (e) {
|
||||
emit(WaterHeaterFailedState(error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
_listenToChanges(deviceId) {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus = WaterHeaterStatusModel.fromJson(
|
||||
usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<WaterHeaterState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
||||
}
|
||||
|
||||
void _startCountdownTimer(
|
||||
Emitter<WaterHeaterState> emit,
|
||||
Duration countdownRemaining,
|
||||
@ -334,8 +375,10 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||
|
||||
if (currentState.countdownRemaining != null && currentState.countdownRemaining! > Duration.zero) {
|
||||
final newRemaining = currentState.countdownRemaining! - const Duration(minutes: 1);
|
||||
if (currentState.countdownRemaining != null &&
|
||||
currentState.countdownRemaining! > Duration.zero) {
|
||||
final newRemaining =
|
||||
currentState.countdownRemaining! - const Duration(minutes: 1);
|
||||
|
||||
if (newRemaining <= Duration.zero) {
|
||||
_countdownTimer?.cancel();
|
||||
@ -430,7 +473,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _revertValue(String code, dynamic oldValue, void Function(WaterHeaterState state) emit) {
|
||||
void _revertValue(String code, dynamic oldValue,
|
||||
void Function(WaterHeaterState state) emit) {
|
||||
_updateLocalValue(code, oldValue);
|
||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||
@ -477,12 +521,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
FutureOr<void> _getSchedule(GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
FutureOr<void> _getSchedule(
|
||||
GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
emit(ScheduleLoadingState());
|
||||
|
||||
try {
|
||||
List<ScheduleModel> schedules =
|
||||
await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
|
||||
List<ScheduleModel> schedules = await DevicesManagementApi()
|
||||
.getDeviceSchedules(deviceStatus.uuid, event.category);
|
||||
|
||||
emit(WaterHeaterDeviceStatusLoaded(
|
||||
deviceStatus,
|
||||
@ -514,7 +559,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
|
||||
// emit(ScheduleLoadingState());
|
||||
|
||||
bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, currentState.status.uuid);
|
||||
bool success = await DevicesManagementApi()
|
||||
.addScheduleRecord(newSchedule, currentState.status.uuid);
|
||||
|
||||
if (success) {
|
||||
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
|
||||
@ -525,7 +571,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onEditSchedule(EditWaterHeaterScheduleEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
FutureOr<void> _onEditSchedule(EditWaterHeaterScheduleEvent event,
|
||||
Emitter<WaterHeaterState> emit) async {
|
||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||
|
||||
@ -594,11 +641,13 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
|
||||
// emit(ScheduleLoadingState());
|
||||
|
||||
bool success = await DevicesManagementApi().deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
|
||||
bool success = await DevicesManagementApi()
|
||||
.deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
|
||||
|
||||
if (success) {
|
||||
final updatedSchedules =
|
||||
currentState.schedules.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
|
||||
final updatedSchedules = currentState.schedules
|
||||
.where((schedule) => schedule.scheduleId != event.scheduleId)
|
||||
.toList();
|
||||
|
||||
emit(currentState.copyWith(schedules: updatedSchedules));
|
||||
} else {
|
||||
@ -608,12 +657,15 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event,
|
||||
Emitter<WaterHeaterState> emit) async {
|
||||
emit(WaterHeaterLoadingState());
|
||||
|
||||
try {
|
||||
final status = await DevicesManagementApi().getBatchStatus(event.devicesUuid);
|
||||
deviceStatus = WaterHeaterStatusModel.fromJson(event.devicesUuid.first, status.status);
|
||||
final status =
|
||||
await DevicesManagementApi().getBatchStatus(event.devicesUuid);
|
||||
deviceStatus = WaterHeaterStatusModel.fromJson(
|
||||
event.devicesUuid.first, status.status);
|
||||
|
||||
emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
@ -621,7 +673,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event,
|
||||
Emitter<WaterHeaterState> emit) async {
|
||||
if (state is WaterHeaterDeviceStatusLoaded) {
|
||||
final currentState = state as WaterHeaterDeviceStatusLoaded;
|
||||
|
||||
|
@ -54,6 +54,15 @@ final class WaterHeaterFetchStatusEvent extends WaterHeaterEvent {
|
||||
|
||||
final class DecrementCountdownEvent extends WaterHeaterEvent {}
|
||||
|
||||
|
||||
class StatusUpdated extends WaterHeaterEvent {
|
||||
final WaterHeaterStatusModel deviceStatus;
|
||||
const StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
||||
|
||||
final class AddScheduleEvent extends WaterHeaterEvent {
|
||||
final List<bool> selectedDays;
|
||||
final TimeOfDay time;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:firebase_database/firebase_database.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/water_leak/bloc/water_leak_event.dart';
|
||||
@ -21,6 +22,7 @@ class WaterLeakBloc extends Bloc<WaterLeakEvent, WaterLeakState> {
|
||||
on<FetchWaterLeakBatchStatusEvent>(_onFetchBatchStatus);
|
||||
on<FetchWaterLeakReportsEvent>(_onFetchWaterLeakReports);
|
||||
on<WaterLeakFactoryResetEvent>(_onFactoryReset);
|
||||
on<StatusUpdated>(_onStatusUpdated);
|
||||
}
|
||||
|
||||
Future<void> _onFetchWaterLeakStatus(
|
||||
@ -30,12 +32,43 @@ class WaterLeakBloc extends Bloc<WaterLeakEvent, WaterLeakState> {
|
||||
final response =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = WaterLeakStatusModel.fromJson(deviceId, response.status);
|
||||
_listenToChanges();
|
||||
emit(WaterLeakLoadedState(deviceStatus!));
|
||||
} catch (e) {
|
||||
emit(WaterLeakErrorState(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
_listenToChanges() {
|
||||
try {
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
|
||||
List<Status> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList
|
||||
.add(Status(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus =
|
||||
WaterLeakStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
if (!isClosed) {
|
||||
add(StatusUpdated(deviceStatus!));
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void _onStatusUpdated(StatusUpdated event, Emitter<WaterLeakState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(WaterLeakLoadedState(deviceStatus!));
|
||||
}
|
||||
|
||||
Future<void> _onControl(
|
||||
WaterLeakControlEvent event, Emitter<WaterLeakState> emit) async {
|
||||
final oldValue = deviceStatus!.watersensorState;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/water_leak/model/water_leak_status_model.dart';
|
||||
|
||||
abstract class WaterLeakEvent extends Equatable {
|
||||
const WaterLeakEvent();
|
||||
@ -17,6 +18,13 @@ class FetchWaterLeakStatusEvent extends WaterLeakEvent {
|
||||
List<Object> get props => [deviceId];
|
||||
}
|
||||
|
||||
class StatusUpdated extends WaterLeakEvent {
|
||||
final WaterLeakStatusModel deviceStatus;
|
||||
const StatusUpdated(this.deviceStatus);
|
||||
@override
|
||||
List<Object> get props => [deviceStatus];
|
||||
}
|
||||
|
||||
class WaterLeakControlEvent extends WaterLeakEvent {
|
||||
final String deviceId;
|
||||
final String code;
|
||||
|
@ -1,56 +1,99 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/services/home_api.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
|
||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
final Graph graph = Graph()..isTree = true;
|
||||
final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
||||
List<Node> sourcesList = [];
|
||||
List<Node> destinationsList = [];
|
||||
// final Graph graph = Graph()..isTree = true;
|
||||
// final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
|
||||
// List<Node> sourcesList = [];
|
||||
// List<Node> destinationsList = [];
|
||||
UserModel? user;
|
||||
String terms = '';
|
||||
String policy = '';
|
||||
|
||||
HomeBloc() : super((HomeInitial())) {
|
||||
on<CreateNewNode>(_createNode);
|
||||
// on<CreateNewNode>(_createNode);
|
||||
on<FetchUserInfo>(_fetchUserInfo);
|
||||
on<FetchTermEvent>(_fetchTerms);
|
||||
on<FetchPolicyEvent>(_fetchPolicy);
|
||||
on<ConfirmUserAgreementEvent>(_confirmUserAgreement);
|
||||
}
|
||||
|
||||
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||
emit(HomeInitial());
|
||||
sourcesList.add(event.sourceNode);
|
||||
destinationsList.add(event.destinationNode);
|
||||
for (int i = 0; i < sourcesList.length; i++) {
|
||||
graph.addEdge(sourcesList[i], destinationsList[i]);
|
||||
}
|
||||
// void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||
// emit(HomeInitial());
|
||||
// sourcesList.add(event.sourceNode);
|
||||
// destinationsList.add(event.destinationNode);
|
||||
// for (int i = 0; i < sourcesList.length; i++) {
|
||||
// graph.addEdge(sourcesList[i], destinationsList[i]);
|
||||
// }
|
||||
|
||||
builder
|
||||
..siblingSeparation = (100)
|
||||
..levelSeparation = (150)
|
||||
..subtreeSeparation = (150)
|
||||
..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
||||
emit(HomeUpdateTree(graph: graph, builder: builder));
|
||||
}
|
||||
// builder
|
||||
// ..siblingSeparation = (100)
|
||||
// ..levelSeparation = (150)
|
||||
// ..subtreeSeparation = (150)
|
||||
// ..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
|
||||
// emit(HomeUpdateTree(graph: graph, builder: builder));
|
||||
// }
|
||||
|
||||
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
user = await HomeApi().fetchUserInfo(uuid);
|
||||
add(FetchTermEvent());
|
||||
add(FetchPolicyEvent());
|
||||
|
||||
emit(HomeInitial());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future _fetchTerms(FetchTermEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
terms = await HomeApi().fetchTerms();
|
||||
emit(HomeInitial());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future _fetchPolicy(FetchPolicyEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
policy = await HomeApi().fetchPolicy();
|
||||
emit(HomeInitial());
|
||||
} catch (e) {
|
||||
debugPrint("Error fetching policy: $e");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future _confirmUserAgreement(
|
||||
ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
policy = await HomeApi().confirmUserAgreements(uuid);
|
||||
emit(PolicyAgreement());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// static Future fetchUserInfo() async {
|
||||
// try {
|
||||
// var uuid =
|
||||
@ -63,7 +106,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
|
||||
List<HomeItemModel> homeItems = [
|
||||
HomeItemModel(
|
||||
title: 'Access',
|
||||
title: 'Access Management',
|
||||
icon: Assets.accessIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
@ -81,7 +124,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
color: ColorsManager.primaryColor,
|
||||
),
|
||||
HomeItemModel(
|
||||
title: 'Devices',
|
||||
title: 'Devices Management',
|
||||
icon: Assets.devicesIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
@ -91,6 +134,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
},
|
||||
color: ColorsManager.primaryColor,
|
||||
),
|
||||
|
||||
// HomeItemModel(
|
||||
// title: 'Move in',
|
||||
// icon: Assets.moveinIcon,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
|
||||
abstract class HomeEvent extends Equatable {
|
||||
const HomeEvent();
|
||||
@ -8,16 +8,22 @@ abstract class HomeEvent extends Equatable {
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class CreateNewNode extends HomeEvent {
|
||||
final Node sourceNode;
|
||||
final Node destinationNode;
|
||||
const CreateNewNode(
|
||||
{required this.sourceNode, required this.destinationNode});
|
||||
// class CreateNewNode extends HomeEvent {
|
||||
// final Node sourceNode;
|
||||
// final Node destinationNode;
|
||||
// const CreateNewNode(
|
||||
// {required this.sourceNode, required this.destinationNode});
|
||||
|
||||
@override
|
||||
List<Object> get props => [sourceNode, destinationNode];
|
||||
}
|
||||
// @override
|
||||
// List<Object> get props => [sourceNode, destinationNode];
|
||||
// }
|
||||
|
||||
class FetchUserInfo extends HomeEvent {
|
||||
const FetchUserInfo();
|
||||
}
|
||||
}
|
||||
|
||||
class FetchTermEvent extends HomeEvent {}
|
||||
|
||||
class FetchPolicyEvent extends HomeEvent {}
|
||||
|
||||
class ConfirmUserAgreementEvent extends HomeEvent {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
|
||||
abstract class HomeState extends Equatable {
|
||||
const HomeState();
|
||||
@ -8,19 +8,25 @@ abstract class HomeState extends Equatable {
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class LoadingHome extends HomeState {}
|
||||
|
||||
class HomeInitial extends HomeState {}
|
||||
|
||||
class HomeCounterState extends HomeState {
|
||||
final int counter;
|
||||
const HomeCounterState(this.counter);
|
||||
}
|
||||
class TermsAgreement extends HomeState {}
|
||||
|
||||
class HomeUpdateTree extends HomeState {
|
||||
final Graph graph;
|
||||
final BuchheimWalkerConfiguration builder;
|
||||
class PolicyAgreement extends HomeState {}
|
||||
|
||||
const HomeUpdateTree({required this.graph, required this.builder});
|
||||
// class HomeCounterState extends HomeState {
|
||||
// final int counter;
|
||||
// const HomeCounterState(this.counter);
|
||||
// }
|
||||
|
||||
@override
|
||||
List<Object> get props => [graph, builder];
|
||||
}
|
||||
// class HomeUpdateTree extends HomeState {
|
||||
// final Graph graph;
|
||||
// final BuchheimWalkerConfiguration builder;
|
||||
|
||||
// const HomeUpdateTree({required this.graph, required this.builder});
|
||||
|
||||
// @override
|
||||
// List<Object> get props => [graph, builder];
|
||||
// }
|
||||
|
178
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
178
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
@ -0,0 +1,178 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class AgreementAndPrivacyDialog extends StatefulWidget {
|
||||
final String terms;
|
||||
final String policy;
|
||||
|
||||
const AgreementAndPrivacyDialog({
|
||||
super.key,
|
||||
required this.terms,
|
||||
required this.policy,
|
||||
});
|
||||
|
||||
@override
|
||||
_AgreementAndPrivacyDialogState createState() =>
|
||||
_AgreementAndPrivacyDialogState();
|
||||
}
|
||||
|
||||
class _AgreementAndPrivacyDialogState extends State<AgreementAndPrivacyDialog> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
bool _isAtEnd = false;
|
||||
int _currentPage = 1;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController.addListener(_onScroll);
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||
}
|
||||
|
||||
void _checkScrollRequirement() {
|
||||
final scrollPosition = _scrollController.position;
|
||||
if (scrollPosition.maxScrollExtent <= 0) {
|
||||
setState(() {
|
||||
_isAtEnd = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.removeListener(_onScroll);
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onScroll() {
|
||||
if (_scrollController.position.atEdge) {
|
||||
final isAtBottom = _scrollController.position.pixels ==
|
||||
_scrollController.position.maxScrollExtent;
|
||||
if (isAtBottom && !_isAtEnd) {
|
||||
setState(() {
|
||||
_isAtEnd = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String get _dialogTitle =>
|
||||
_currentPage == 1 ? 'User Agreement' : 'Privacy Policy';
|
||||
|
||||
String get _dialogContent => _currentPage == 1 ? widget.terms : widget.policy;
|
||||
final String staticText =
|
||||
'<h5 style="color: #FF5722;">If you cancel you will be logged out.</h5>';
|
||||
|
||||
Widget _buildScrollableContent() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(40),
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
height: MediaQuery.of(context).size.height * 0.75,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[200],
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: Scrollbar(
|
||||
thumbVisibility: true,
|
||||
trackVisibility: true,
|
||||
interactive: true,
|
||||
controller: _scrollController,
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.all(25),
|
||||
child: Html(
|
||||
data: "$_dialogContent $staticText",
|
||||
onLinkTap: (url, attributes, element) async {
|
||||
if (url != null) {
|
||||
final uri = Uri.parse(url);
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
}
|
||||
},
|
||||
style: {
|
||||
"body": Style(
|
||||
fontSize: FontSize(14),
|
||||
color: Colors.black87,
|
||||
lineHeight: LineHeight(1.5),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButton() {
|
||||
final String buttonText = _currentPage == 2 ? "I Agree" : "Next";
|
||||
|
||||
return InkWell(
|
||||
onTap: _isAtEnd
|
||||
? () {
|
||||
if (_currentPage == 1) {
|
||||
setState(() {
|
||||
_currentPage = 2;
|
||||
_isAtEnd = false;
|
||||
_scrollController.jumpTo(0);
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||
});
|
||||
} else {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Text(
|
||||
buttonText,
|
||||
style: TextStyle(
|
||||
color: _isAtEnd ? ColorsManager.secondaryColor : Colors.grey,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
_dialogTitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: ColorsManager.secondaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
_buildScrollableContent(),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
AuthBloc.logout();
|
||||
context.go(RoutesConst.auth);
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
_buildActionButton(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -41,8 +41,7 @@ class HomeMobilePage extends StatelessWidget {
|
||||
SizedBox(height: size.height * 0.05),
|
||||
const Text(
|
||||
'ACCESS YOUR APPS',
|
||||
style:
|
||||
TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Expanded(
|
||||
@ -51,9 +50,8 @@ class HomeMobilePage extends StatelessWidget {
|
||||
height: size.height * 0.6,
|
||||
width: size.width * 0.68,
|
||||
child: GridView.builder(
|
||||
itemCount: 8,
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
itemCount: 3,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 20.0,
|
||||
mainAxisSpacing: 20.0,
|
||||
@ -65,8 +63,7 @@ class HomeMobilePage extends StatelessWidget {
|
||||
active: homeItems[index]['active'],
|
||||
name: homeItems[index]['title'],
|
||||
img: homeItems[index]['icon'],
|
||||
onTap: () =>
|
||||
homeBloc.homeItems[index].onPress(context),
|
||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -97,33 +94,33 @@ class HomeMobilePage extends StatelessWidget {
|
||||
'icon': Assets.devicesIcon,
|
||||
'active': true,
|
||||
},
|
||||
{
|
||||
'title': 'Move in',
|
||||
'icon': Assets.moveinIcon,
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Construction',
|
||||
'icon': Assets.constructionIcon,
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Energy',
|
||||
'icon': Assets.energyIcon,
|
||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Integrations',
|
||||
'icon': Assets.integrationsIcon,
|
||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
'active': false,
|
||||
},
|
||||
{
|
||||
'title': 'Asset',
|
||||
'icon': Assets.assetIcon,
|
||||
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
'active': false,
|
||||
},
|
||||
// {
|
||||
// 'title': 'Move in',
|
||||
// 'icon': Assets.moveinIcon,
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Construction',
|
||||
// 'icon': Assets.constructionIcon,
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Energy',
|
||||
// 'icon': Assets.energyIcon,
|
||||
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Integrations',
|
||||
// 'icon': Assets.integrationsIcon,
|
||||
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
// 'active': false,
|
||||
// },
|
||||
// {
|
||||
// 'title': 'Asset',
|
||||
// 'icon': Assets.assetIcon,
|
||||
// 'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||
// 'active': false,
|
||||
// },
|
||||
];
|
||||
}
|
||||
|
@ -1,80 +1,129 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/view/agreement_and_privacy_dialog.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/pages/home/view/home_card.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
|
||||
class HomeWebPage extends StatelessWidget {
|
||||
class HomeWebPage extends StatefulWidget {
|
||||
const HomeWebPage({super.key});
|
||||
|
||||
@override
|
||||
State<HomeWebPage> createState() => _HomeWebPageState();
|
||||
}
|
||||
|
||||
class _HomeWebPageState extends State<HomeWebPage> {
|
||||
// Flag to track whether the dialog is already shown.
|
||||
bool _dialogShown = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
homeBloc.add(FetchUserInfo());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size size = MediaQuery.of(context).size;
|
||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) => false,
|
||||
child: BlocConsumer<HomeBloc, HomeState>(
|
||||
listener: (BuildContext context, state) {},
|
||||
builder: (context, state) {
|
||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
return WebScaffold(
|
||||
enableMenuSidebar: false,
|
||||
appBarTitle: Row(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) => false,
|
||||
child: BlocConsumer<HomeBloc, HomeState>(
|
||||
listener: (BuildContext context, state) {
|
||||
if (state is HomeInitial) {
|
||||
if (homeBloc.user!.hasAcceptedWebAgreement == false && !_dialogShown) {
|
||||
_dialogShown = true; // Set the flag to true to indicate the dialog is showing.
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AgreementAndPrivacyDialog(
|
||||
terms: homeBloc.terms,
|
||||
policy: homeBloc.policy,
|
||||
);
|
||||
},
|
||||
).then((v) {
|
||||
_dialogShown = false;
|
||||
if (v != null) {
|
||||
homeBloc.add(ConfirmUserAgreementEvent());
|
||||
homeBloc.add(const FetchUserInfo());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
return WebScaffold(
|
||||
enableMenuSidebar: false,
|
||||
appBarTitle: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.loginLogo,
|
||||
width: 150,
|
||||
),
|
||||
],
|
||||
),
|
||||
scaffoldBody: SizedBox(
|
||||
height: size.height,
|
||||
width: size.width,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.loginLogo,
|
||||
width: 150,
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(height: size.height * 0.1),
|
||||
Text(
|
||||
'ACCESS YOUR APPS',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge!
|
||||
.copyWith(color: Colors.black, fontSize: 40),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: SizedBox(
|
||||
height: size.height * 0.6,
|
||||
width: size.width * 0.68,
|
||||
child: GridView.builder(
|
||||
itemCount: 3, // Change this count if needed.
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3, // Adjust as needed.
|
||||
crossAxisSpacing: 20.0,
|
||||
mainAxisSpacing: 20.0,
|
||||
childAspectRatio: 1.5,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return HomeCard(
|
||||
index: index,
|
||||
active: homeBloc.homeItems[index].active!,
|
||||
name: homeBloc.homeItems[index].title!,
|
||||
img: homeBloc.homeItems[index].icon!,
|
||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
scaffoldBody: SizedBox(
|
||||
height: size.height,
|
||||
width: size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(height: size.height * 0.1),
|
||||
Text(
|
||||
'ACCESS YOUR APPS',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge!
|
||||
.copyWith(color: Colors.black, fontSize: 40),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: SizedBox(
|
||||
height: size.height * 0.6,
|
||||
width: size.width * 0.68,
|
||||
child: GridView.builder(
|
||||
itemCount: 3, //8
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
crossAxisSpacing: 20.0,
|
||||
mainAxisSpacing: 20.0,
|
||||
childAspectRatio: 1.5,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return HomeCard(
|
||||
index: index,
|
||||
active: homeBloc.homeItems[index].active!,
|
||||
name: homeBloc.homeItems[index].title!,
|
||||
img: homeBloc.homeItems[index].icon!,
|
||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
));
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,185 +1,185 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:graphview/GraphView.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
// import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
// import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
// import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
|
||||
class TreeWidget extends StatelessWidget {
|
||||
const TreeWidget({super.key});
|
||||
// class TreeWidget extends StatelessWidget {
|
||||
// const TreeWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
String firstNodeName = '';
|
||||
String secondNodeName = '';
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// // final HomeBloc homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
// String firstNodeName = '';
|
||||
// String secondNodeName = '';
|
||||
|
||||
return SafeArea(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
height: MediaQuery.sizeOf(context).height,
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
||||
if (state is HomeInitial) {
|
||||
return Wrap(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Subtree separation"),
|
||||
onChanged: (text) {
|
||||
firstNodeName = text;
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Container(
|
||||
width: 100,
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(labelText: "Node Name"),
|
||||
onChanged: (text) {
|
||||
secondNodeName = text;
|
||||
},
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
final node1 = Node.Id(firstNodeName);
|
||||
final node2 = Node.Id(secondNodeName);
|
||||
context.read<HomeBloc>().add(CreateNewNode(
|
||||
sourceNode: node1, destinationNode: node2));
|
||||
},
|
||||
child: Text("Add"),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
if (state is HomeUpdateTree) {
|
||||
return Expanded(
|
||||
child: InteractiveViewer(
|
||||
constrained: false,
|
||||
boundaryMargin: const EdgeInsets.all(100),
|
||||
minScale: 0.01,
|
||||
maxScale: 5.6,
|
||||
child: GraphView(
|
||||
graph: state.graph,
|
||||
algorithm: BuchheimWalkerAlgorithm(
|
||||
state.builder, TreeEdgeRenderer(state.builder)),
|
||||
paint: Paint()
|
||||
..color = Colors.green
|
||||
..strokeWidth = 1
|
||||
..style = PaintingStyle.stroke,
|
||||
builder: (Node node) {
|
||||
// I can decide what widget should be shown here based on the id
|
||||
var nodeName = node.key!.value;
|
||||
return rectangleWidget(nodeName, node, context);
|
||||
},
|
||||
)),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// return SafeArea(
|
||||
// child: Container(
|
||||
// padding: const EdgeInsets.all(24),
|
||||
// width: MediaQuery.sizeOf(context).width,
|
||||
// height: MediaQuery.sizeOf(context).height,
|
||||
// alignment: AlignmentDirectional.center,
|
||||
// child: Column(
|
||||
// mainAxisSize: MainAxisSize.max,
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
|
||||
// if (state is HomeInitial) {
|
||||
// return Wrap(
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: 100,
|
||||
// child: TextFormField(
|
||||
// decoration: const InputDecoration(
|
||||
// labelText: "Subtree separation"),
|
||||
// onChanged: (text) {
|
||||
// firstNodeName = text;
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// width: 8,
|
||||
// ),
|
||||
// Container(
|
||||
// width: 100,
|
||||
// child: TextFormField(
|
||||
// decoration: InputDecoration(labelText: "Node Name"),
|
||||
// onChanged: (text) {
|
||||
// secondNodeName = text;
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// final node1 = Node.Id(firstNodeName);
|
||||
// final node2 = Node.Id(secondNodeName);
|
||||
// context.read<HomeBloc>().add(CreateNewNode(
|
||||
// sourceNode: node1, destinationNode: node2));
|
||||
// },
|
||||
// child: Text("Add"),
|
||||
// )
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
// if (state is HomeUpdateTree) {
|
||||
// return Expanded(
|
||||
// child: InteractiveViewer(
|
||||
// constrained: false,
|
||||
// boundaryMargin: const EdgeInsets.all(100),
|
||||
// minScale: 0.01,
|
||||
// maxScale: 5.6,
|
||||
// child: GraphView(
|
||||
// graph: state.graph,
|
||||
// algorithm: BuchheimWalkerAlgorithm(
|
||||
// state.builder, TreeEdgeRenderer(state.builder)),
|
||||
// paint: Paint()
|
||||
// ..color = Colors.green
|
||||
// ..strokeWidth = 1
|
||||
// ..style = PaintingStyle.stroke,
|
||||
// builder: (Node node) {
|
||||
// // I can decide what widget should be shown here based on the id
|
||||
// var nodeName = node.key!.value;
|
||||
// return rectangleWidget(nodeName, node, context);
|
||||
// },
|
||||
// )),
|
||||
// );
|
||||
// } else {
|
||||
// return Container();
|
||||
// }
|
||||
// })
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
||||
String nodeName = '';
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: blocContext,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Add a child'),
|
||||
content: TextField(
|
||||
decoration:
|
||||
const InputDecoration(hintText: 'Enter your text here'),
|
||||
onChanged: (value) {
|
||||
nodeName = value;
|
||||
},
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text('Close'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (nodeName.isNotEmpty) {
|
||||
final newNode = Node.Id(nodeName);
|
||||
blocContext.read<HomeBloc>().add(CreateNewNode(
|
||||
sourceNode: node, destinationNode: newNode));
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text('Add'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: MediaQuery.of(blocContext).size.width * 0.2,
|
||||
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||
padding: EdgeInsets.all(20.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 3), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
child: Icon(
|
||||
Icons.location_on,
|
||||
color: Colors.blue,
|
||||
size: 40.0,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10.0),
|
||||
SizedBox(
|
||||
child: Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
fontSize: 24.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Container(
|
||||
child: const Icon(
|
||||
Icons.add_circle_outline,
|
||||
color: Colors.grey,
|
||||
size: 24.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
// Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
|
||||
// String nodeName = '';
|
||||
// return InkWell(
|
||||
// onTap: () {
|
||||
// showDialog(
|
||||
// context: blocContext,
|
||||
// builder: (BuildContext context) {
|
||||
// return AlertDialog(
|
||||
// title: const Text('Add a child'),
|
||||
// content: TextField(
|
||||
// decoration:
|
||||
// const InputDecoration(hintText: 'Enter your text here'),
|
||||
// onChanged: (value) {
|
||||
// nodeName = value;
|
||||
// },
|
||||
// ),
|
||||
// actions: <Widget>[
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// child: Text('Close'),
|
||||
// ),
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// if (nodeName.isNotEmpty) {
|
||||
// final newNode = Node.Id(nodeName);
|
||||
// blocContext.read<HomeBloc>().add(CreateNewNode(
|
||||
// sourceNode: node, destinationNode: newNode));
|
||||
// }
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// child: Text('Add'),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// },
|
||||
// child: Container(
|
||||
// width: MediaQuery.of(blocContext).size.width * 0.2,
|
||||
// margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
|
||||
// padding: EdgeInsets.all(20.0),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(10.0),
|
||||
// boxShadow: [
|
||||
// BoxShadow(
|
||||
// color: Colors.grey.withOpacity(0.5),
|
||||
// spreadRadius: 2,
|
||||
// blurRadius: 5,
|
||||
// offset: Offset(0, 3), // changes position of shadow
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// const SizedBox(
|
||||
// child: Icon(
|
||||
// Icons.location_on,
|
||||
// color: Colors.blue,
|
||||
// size: 40.0,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 10.0),
|
||||
// SizedBox(
|
||||
// child: Text(
|
||||
// text,
|
||||
// style: const TextStyle(
|
||||
// fontSize: 24.0,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// const Spacer(),
|
||||
// Container(
|
||||
// child: const Icon(
|
||||
// Icons.add_circle_outline,
|
||||
// color: Colors.grey,
|
||||
// size: 24.0,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
@ -42,7 +42,9 @@ class RolesUserModel {
|
||||
invitedBy:
|
||||
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
|
||||
phoneNumber: json['phoneNumber'],
|
||||
jobTitle: json['jobTitle'] ?? "-",
|
||||
jobTitle: json['jobTitle'] == null || json['jobTitle'] == " "
|
||||
? "_"
|
||||
: json['jobTitle'],
|
||||
createdDate: json['createdDate'],
|
||||
createdTime: json['createdTime'],
|
||||
);
|
||||
|
@ -79,13 +79,14 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
|
||||
List<TreeNode> updatedCommunities = [];
|
||||
List<TreeNode> spacesNodes = [];
|
||||
|
||||
List<String> communityIds = [];
|
||||
_onLoadCommunityAndSpaces(
|
||||
LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
List<CommunityModel> communities =
|
||||
await CommunitySpaceManagementApi().fetchCommunities();
|
||||
communityIds = communities.map((community) => community.uuid).toList();
|
||||
updatedCommunities = await Future.wait(
|
||||
communities.map((community) async {
|
||||
List<SpaceModel> spaces =
|
||||
@ -101,13 +102,19 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
originalCommunities = updatedCommunities;
|
||||
emit(const SpacesLoadedState());
|
||||
return updatedCommunities;
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
// This variable holds the full original list.
|
||||
List<TreeNode> originalCommunities = [];
|
||||
|
||||
// This variable holds the working list that may be filtered.
|
||||
|
||||
// Build tree nodes from your data model.
|
||||
List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||
return spaces.map((space) {
|
||||
List<TreeNode> childNodes =
|
||||
@ -123,12 +130,39 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Optional helper method to deep clone a TreeNode.
|
||||
TreeNode _cloneNode(TreeNode node) {
|
||||
return TreeNode(
|
||||
uuid: node.uuid,
|
||||
title: node.title,
|
||||
isChecked: node.isChecked,
|
||||
isHighlighted: node.isHighlighted,
|
||||
isExpanded: node.isExpanded,
|
||||
children: node.children.map(_cloneNode).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
// Clone an entire list of tree nodes.
|
||||
List<TreeNode> _cloneNodes(List<TreeNode> nodes) {
|
||||
return nodes.map(_cloneNode).toList();
|
||||
}
|
||||
|
||||
// Your search event handler.
|
||||
void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
|
||||
// If the search term is empty, restore the original list.
|
||||
if (event.searchTerm!.isEmpty) {
|
||||
// Clear any highlights on the restored copy.
|
||||
updatedCommunities = _cloneNodes(originalCommunities);
|
||||
_clearHighlights(updatedCommunities);
|
||||
} else {
|
||||
_searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
|
||||
// Start with a fresh clone of the original tree.
|
||||
List<TreeNode> freshClone = _cloneNodes(originalCommunities);
|
||||
|
||||
_searchAndHighlightNodes(freshClone, event.searchTerm!);
|
||||
|
||||
updatedCommunities = _filterNodes(freshClone, event.searchTerm!);
|
||||
}
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
@ -155,6 +189,91 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
return anyMatch;
|
||||
}
|
||||
|
||||
List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
|
||||
List<TreeNode> filteredNodes = [];
|
||||
for (var node in nodes) {
|
||||
bool isMatch =
|
||||
node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||
List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);
|
||||
if (isMatch || filteredChildren.isNotEmpty) {
|
||||
node.isHighlighted = isMatch;
|
||||
node.children = filteredChildren;
|
||||
filteredNodes.add(node);
|
||||
}
|
||||
}
|
||||
return filteredNodes;
|
||||
}
|
||||
|
||||
// List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||
// return spaces.map((space) {
|
||||
// List<TreeNode> childNodes =
|
||||
// space.children.isNotEmpty ? _buildTreeNodes(space.children) : [];
|
||||
// return TreeNode(
|
||||
// uuid: space.uuid!,
|
||||
// title: space.name,
|
||||
// isChecked: false,
|
||||
// isHighlighted: false,
|
||||
// isExpanded: childNodes.isNotEmpty,
|
||||
// children: childNodes,
|
||||
// );
|
||||
// }).toList();
|
||||
// }
|
||||
|
||||
// void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||
// emit(UsersLoadingState());
|
||||
// if (event.searchTerm!.isEmpty) {
|
||||
// _clearHighlights(updatedCommunities);
|
||||
// } else {
|
||||
// _searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
|
||||
// updatedCommunities = _filterNodes(updatedCommunities, event.searchTerm!);
|
||||
// }
|
||||
// emit(ChangeStatusSteps());
|
||||
// }
|
||||
|
||||
// void _clearHighlights(List<TreeNode> nodes) {
|
||||
// for (var node in nodes) {
|
||||
// node.isHighlighted = false;
|
||||
// if (node.children.isNotEmpty) {
|
||||
// _clearHighlights(node.children);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// bool _searchAndHighlightNodes(List<TreeNode> nodes, String searchTerm) {
|
||||
// bool anyMatch = false;
|
||||
// for (var node in nodes) {
|
||||
// bool isMatch =
|
||||
// node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||
// bool childMatch = _searchAndHighlightNodes(node.children, searchTerm);
|
||||
// node.isHighlighted = isMatch || childMatch;
|
||||
|
||||
// anyMatch = anyMatch || node.isHighlighted;
|
||||
// }
|
||||
// return anyMatch;
|
||||
// }
|
||||
|
||||
// List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
|
||||
// List<TreeNode> filteredNodes = [];
|
||||
// for (var node in nodes) {
|
||||
// // Check if the current node's title contains the search term.
|
||||
// bool isMatch =
|
||||
// node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||
|
||||
// // Recursively filter the children.
|
||||
// List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);
|
||||
|
||||
// // If the current node is a match or any of its children are, include it.
|
||||
// if (isMatch || filteredChildren.isNotEmpty) {
|
||||
// // Optionally, update any properties (like isHighlighted) if you still need them.
|
||||
// node.isHighlighted = isMatch;
|
||||
// // Replace the children with the filtered ones.
|
||||
// node.children = filteredChildren;
|
||||
// filteredNodes.add(node);
|
||||
// }
|
||||
// }
|
||||
// return filteredNodes;
|
||||
// }
|
||||
|
||||
List<String> selectedIds = [];
|
||||
|
||||
List<String> getSelectedIds(List<TreeNode> nodes) {
|
||||
@ -177,7 +296,6 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
roles = await UserPermissionApi().fetchRoles();
|
||||
// add(PermissionEvent(roleUuid: roles.first.uuid));
|
||||
emit(RolePermissionInitial());
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||
@ -208,10 +326,13 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
return anyMatch;
|
||||
}
|
||||
|
||||
_sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
||||
void _sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||
.where((id) => !communityIds.contains(id))
|
||||
.toList();
|
||||
|
||||
bool res = await UserPermissionApi().sendInviteUser(
|
||||
email: emailController.text,
|
||||
firstName: firstNameController.text,
|
||||
@ -221,7 +342,8 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
roleUuid: roleSelected,
|
||||
spaceUuids: selectedIds,
|
||||
);
|
||||
if (res == true) {
|
||||
|
||||
if (res) {
|
||||
showCustomDialog(
|
||||
barrierDismissible: false,
|
||||
context: event.context,
|
||||
@ -251,7 +373,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||
.where((id) => !communityIds.contains(id))
|
||||
.toList();
|
||||
|
||||
bool res = await UserPermissionApi().editInviteUser(
|
||||
userId: event.userId,
|
||||
firstName: firstNameController.text,
|
||||
|
@ -34,8 +34,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
return Dialog(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
width: 900,
|
||||
child: Column(
|
||||
children: [
|
||||
@ -64,8 +63,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
children: [
|
||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||
_buildStep3Indicator(
|
||||
3, "Role & Permissions", _blocRole),
|
||||
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -113,15 +111,12 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
if (currentStep < 3) {
|
||||
currentStep++;
|
||||
if (currentStep == 2) {
|
||||
_blocRole.add(
|
||||
const CheckStepStatus(isEditUser: false));
|
||||
_blocRole.add(const CheckStepStatus(isEditUser: false));
|
||||
} else if (currentStep == 3) {
|
||||
_blocRole
|
||||
.add(const CheckSpacesStepStatus());
|
||||
_blocRole.add(const CheckSpacesStepStatus());
|
||||
}
|
||||
} else {
|
||||
_blocRole
|
||||
.add(SendInviteUsers(context: context));
|
||||
_blocRole.add(SendInviteUsers(context: context));
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -129,11 +124,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
currentStep < 3 ? "Next" : "Save",
|
||||
style: TextStyle(
|
||||
color: (_blocRole.isCompleteSpaces == false ||
|
||||
_blocRole.isCompleteBasics ==
|
||||
false ||
|
||||
_blocRole
|
||||
.isCompleteRolePermissions ==
|
||||
false) &&
|
||||
_blocRole.isCompleteBasics == false ||
|
||||
_blocRole.isCompleteRolePermissions == false) &&
|
||||
currentStep == 3
|
||||
? ColorsManager.grayColor
|
||||
: ColorsManager.secondaryColor),
|
||||
@ -204,12 +196,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -236,12 +224,16 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
currentStep = step;
|
||||
bloc.add(const CheckStepStatus(isEditUser: false));
|
||||
currentStep = step;
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
bloc.add(const CheckStepStatus(isEditUser: false));
|
||||
});
|
||||
if (step3 == 3) {
|
||||
bloc.add(const CheckRoleStepStatus());
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
bloc.add(const CheckRoleStepStatus());
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
@ -268,12 +260,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -330,12 +318,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -46,117 +46,120 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.18,
|
||||
height: MediaQuery.of(context).size.width * 0.08,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
Flexible(
|
||||
child: SizedBox(
|
||||
// width: MediaQuery.of(context).size.width * 0.18,
|
||||
height: MediaQuery.of(context).size.width * 0.08,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'First Name',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
style:
|
||||
const TextStyle(color: ColorsManager.blackColor),
|
||||
// onChanged: (value) {
|
||||
// Future.delayed(const Duration(milliseconds: 200),
|
||||
// () {
|
||||
// _blocRole.add(const ValidateBasicsStep());
|
||||
// });
|
||||
// },
|
||||
controller: _blocRole.firstNameController,
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "Enter first name",
|
||||
).copyWith(
|
||||
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Enter first name';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.18,
|
||||
height: MediaQuery.of(context).size.width * 0.08,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text('Last Name',
|
||||
Text(
|
||||
'First Name',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
)),
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
// onChanged: (value) {
|
||||
// Future.delayed(const Duration(milliseconds: 200),
|
||||
// () {
|
||||
// _blocRole.add(ValidateBasicsStep());
|
||||
// });
|
||||
// },
|
||||
controller: _blocRole.lastNameController,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration:
|
||||
inputTextFormDeco(hintText: "Enter last name")
|
||||
.copyWith(
|
||||
hintStyle: context
|
||||
.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray)),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Enter last name';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
style: const TextStyle(
|
||||
color: ColorsManager.blackColor),
|
||||
// onChanged: (value) {
|
||||
// Future.delayed(const Duration(milliseconds: 200),
|
||||
// () {
|
||||
// _blocRole.add(const ValidateBasicsStep());
|
||||
// });
|
||||
// },
|
||||
controller: _blocRole.firstNameController,
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "Enter first name",
|
||||
).copyWith(
|
||||
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Enter first name';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: SizedBox(
|
||||
// width: MediaQuery.of(context).size.width * 0.18,
|
||||
height: MediaQuery.of(context).size.width * 0.08,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text('Last Name',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
)),
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
// onChanged: (value) {
|
||||
// Future.delayed(const Duration(milliseconds: 200),
|
||||
// () {
|
||||
// _blocRole.add(ValidateBasicsStep());
|
||||
// });
|
||||
// },
|
||||
controller: _blocRole.lastNameController,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration:
|
||||
inputTextFormDeco(hintText: "Enter last name")
|
||||
.copyWith(
|
||||
hintStyle: context.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray)),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Enter last name';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -218,7 +221,7 @@ class BasicsView extends StatelessWidget {
|
||||
if (_blocRole.checkEmailValid != "Valid email") {
|
||||
return _blocRole.checkEmailValid;
|
||||
}
|
||||
return null;
|
||||
// return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -81,7 +81,7 @@ Future<void> showPopUpFilterMenu({
|
||||
),
|
||||
const Divider(),
|
||||
const Text(
|
||||
"Filter by Status",
|
||||
"Filter by ",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Container(
|
||||
|
@ -27,7 +27,16 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
int currentPage = 1;
|
||||
List<RolesUserModel> users = [];
|
||||
List<RolesUserModel> initialUsers = [];
|
||||
|
||||
List<RolesUserModel> totalUsersCount = [];
|
||||
String currentSortOrder = '';
|
||||
|
||||
String currentSortJopTitle = '';
|
||||
String currentSortRole = '';
|
||||
String currentSortCreatedDate = '';
|
||||
String currentSortStatus = '';
|
||||
String currentSortCreatedBy = '';
|
||||
|
||||
String currentSortOrderDate = '';
|
||||
List<String> roleTypes = [];
|
||||
List<String> jobTitle = [];
|
||||
@ -40,9 +49,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
roleTypes.clear();
|
||||
jobTitle.clear();
|
||||
createdBy.clear();
|
||||
// deActivate.clear();
|
||||
users = await UserPermissionApi().fetchUsers();
|
||||
|
||||
users.sort((a, b) {
|
||||
final dateA = _parseDateTime(a.createdDate);
|
||||
final dateB = _parseDateTime(b.createdDate);
|
||||
@ -57,15 +64,13 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
for (var user in users) {
|
||||
createdBy.add(user.invitedBy.toString());
|
||||
}
|
||||
// for (var user in users) {
|
||||
// deActivate.add(user.status.toString());
|
||||
// }
|
||||
initialUsers = List.from(users);
|
||||
roleTypes = roleTypes.toSet().toList();
|
||||
jobTitle = jobTitle.toSet().toList();
|
||||
createdBy = createdBy.toSet().toList();
|
||||
// deActivate = deActivate.toSet().toList();
|
||||
_handlePageChange(ChangePage(1), emit);
|
||||
totalUsersCount = initialUsers;
|
||||
add(ChangePage(currentPage));
|
||||
emit(UsersLoadedState(users: users));
|
||||
} catch (e) {
|
||||
emit(ErrorState(e.toString()));
|
||||
@ -96,26 +101,6 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
event.userId, event.newStatus == "disabled" ? false : true);
|
||||
if (res == true) {
|
||||
add(const GetUsers());
|
||||
// users = users.map((user) {
|
||||
// if (user.uuid == event.userId) {
|
||||
// return RolesUserModel(
|
||||
// uuid: user.uuid,
|
||||
// createdAt: user.createdAt,
|
||||
// email: user.email,
|
||||
// firstName: user.firstName,
|
||||
// lastName: user.lastName,
|
||||
// roleType: user.roleType,
|
||||
// status: event.newStatus,
|
||||
// isEnabled: event.newStatus == "disabled" ? false : true,
|
||||
// invitedBy: user.invitedBy,
|
||||
// phoneNumber: user.phoneNumber,
|
||||
// jobTitle: user.jobTitle,
|
||||
// createdDate: user.createdDate,
|
||||
// createdTime: user.createdTime,
|
||||
// );
|
||||
// }
|
||||
// return user;
|
||||
// }).toList();
|
||||
}
|
||||
emit(UsersLoadedState(users: users));
|
||||
} catch (e) {
|
||||
@ -125,11 +110,14 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
|
||||
void _toggleSortUsersByNameAsc(
|
||||
SortUsersByNameAsc event, Emitter<UserTableState> emit) {
|
||||
selectedRoles.clear();
|
||||
selectedJobTitles.clear();
|
||||
selectedCreatedBy.clear();
|
||||
selectedStatuses.clear();
|
||||
if (currentSortOrder == "Asc") {
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
users = List.from(users);
|
||||
emit(UsersLoadedState(users: users));
|
||||
} else {
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "Asc";
|
||||
@ -137,28 +125,42 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.compareTo(b.firstName.toString().toLowerCase()));
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
currentSortJopTitle = '';
|
||||
currentSortCreatedDate = '';
|
||||
currentSortStatus = '';
|
||||
currentSortCreatedBy = '';
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
|
||||
void _toggleSortUsersByNameDesc(
|
||||
SortUsersByNameDesc event, Emitter<UserTableState> emit) {
|
||||
selectedRoles.clear();
|
||||
selectedJobTitles.clear();
|
||||
selectedCreatedBy.clear();
|
||||
selectedStatuses.clear();
|
||||
if (currentSortOrder == "Desc") {
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
users = List.from(initialUsers); // Reset to saved initial state
|
||||
emit(UsersLoadedState(users: users));
|
||||
users = List.from(initialUsers);
|
||||
} else {
|
||||
// Sort descending
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "Desc";
|
||||
users.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
currentSortJopTitle = '';
|
||||
currentSortCreatedDate = '';
|
||||
currentSortStatus = '';
|
||||
currentSortCreatedBy = '';
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
|
||||
void _toggleSortUsersByDateNewestToOldest(
|
||||
DateNewestToOldestEvent event, Emitter<UserTableState> emit) {
|
||||
selectedRoles.clear();
|
||||
selectedJobTitles.clear();
|
||||
selectedCreatedBy.clear();
|
||||
selectedStatuses.clear();
|
||||
if (currentSortOrderDate == "NewestToOldest") {
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
@ -179,6 +181,10 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
|
||||
void _toggleSortUsersByDateOldestToNewest(
|
||||
DateOldestToNewestEvent event, Emitter<UserTableState> emit) {
|
||||
selectedRoles.clear();
|
||||
selectedJobTitles.clear();
|
||||
selectedCreatedBy.clear();
|
||||
selectedStatuses.clear();
|
||||
if (currentSortOrderDate == "OldestToNewest") {
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
@ -212,6 +218,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
Future<void> _searchUsers(
|
||||
SearchUsers event, Emitter<UserTableState> emit) async {
|
||||
try {
|
||||
emit(TableSearch());
|
||||
final query = event.query.toLowerCase();
|
||||
final filteredUsers = initialUsers.where((user) {
|
||||
final fullName = "${user.firstName} ${user.lastName}".toLowerCase();
|
||||
@ -240,7 +247,8 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
}
|
||||
|
||||
void _handlePageChange(ChangePage event, Emitter<UserTableState> emit) {
|
||||
const itemsPerPage = 10;
|
||||
currentPage = event.pageNumber;
|
||||
const itemsPerPage = 20;
|
||||
final startIndex = (event.pageNumber - 1) * itemsPerPage;
|
||||
final endIndex = startIndex + itemsPerPage;
|
||||
if (startIndex >= users.length) {
|
||||
@ -277,9 +285,15 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
} else if (event.sortOrder == "Desc") {
|
||||
currentSortOrder = "Desc";
|
||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||
} else {
|
||||
currentSortOrder = "";
|
||||
}
|
||||
} else {}
|
||||
currentSortOrder = "";
|
||||
currentSortCreatedDate = '';
|
||||
currentSortStatus = '';
|
||||
currentSortCreatedBy = '';
|
||||
currentSortJopTitle = '';
|
||||
currentSortOrderDate = "";
|
||||
|
||||
totalUsersCount = filteredUsers;
|
||||
|
||||
emit(UsersLoadedState(users: filteredUsers));
|
||||
}
|
||||
@ -301,9 +315,16 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
} else if (event.sortOrder == "Desc") {
|
||||
currentSortOrder = "Desc";
|
||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||
} else {
|
||||
currentSortOrder = "";
|
||||
}
|
||||
} else {}
|
||||
currentSortOrder = "";
|
||||
currentSortCreatedDate = '';
|
||||
currentSortStatus = '';
|
||||
currentSortCreatedBy = '';
|
||||
currentSortRole = '';
|
||||
currentSortOrderDate = "";
|
||||
|
||||
totalUsersCount = filteredUsers;
|
||||
|
||||
emit(UsersLoadedState(users: filteredUsers));
|
||||
}
|
||||
|
||||
@ -325,9 +346,15 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
} else if (event.sortOrder == "Desc") {
|
||||
currentSortOrder = "Desc";
|
||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||
} else {
|
||||
currentSortOrder = "";
|
||||
}
|
||||
} else {}
|
||||
currentSortOrder = '';
|
||||
currentSortRole = '';
|
||||
currentSortCreatedDate = '';
|
||||
currentSortStatus = '';
|
||||
currentSortOrderDate = "";
|
||||
|
||||
totalUsersCount = filteredUsers;
|
||||
|
||||
emit(UsersLoadedState(users: filteredUsers));
|
||||
}
|
||||
|
||||
@ -337,7 +364,20 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
|
||||
final filteredUsers = initialUsers.where((user) {
|
||||
if (selectedStatuses.isEmpty) return true;
|
||||
return selectedStatuses.contains(user.status);
|
||||
|
||||
return selectedStatuses.any((status) {
|
||||
final userStatus = user.status?.toLowerCase() ?? '';
|
||||
switch (status.toLowerCase()) {
|
||||
case 'active':
|
||||
return user.isEnabled == true && userStatus != 'invited';
|
||||
case 'disabled':
|
||||
return user.isEnabled == false;
|
||||
case 'invited':
|
||||
return userStatus == 'invited';
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}).toList();
|
||||
if (event.sortOrder == "Asc") {
|
||||
currentSortOrder = "Asc";
|
||||
@ -348,9 +388,14 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
} else if (event.sortOrder == "Desc") {
|
||||
currentSortOrder = "Desc";
|
||||
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
|
||||
} else {
|
||||
currentSortOrder = "";
|
||||
}
|
||||
totalUsersCount = filteredUsers;
|
||||
} else {}
|
||||
currentSortOrder = '';
|
||||
currentSortRole = '';
|
||||
currentSortCreatedDate = '';
|
||||
currentSortCreatedBy = '';
|
||||
currentSortOrderDate = "";
|
||||
|
||||
emit(UsersLoadedState(users: filteredUsers));
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,10 @@ final class TableInitial extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class TableSearch extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
final class RolesLoadingState extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
|
@ -12,7 +12,7 @@ Future<void> showDateFilterMenu({
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RelativeRect position = RelativeRect.fromRect(
|
||||
Rect.fromLTRB(
|
||||
overlay.size.width / 2,
|
||||
overlay.size.width / 3,
|
||||
240,
|
||||
0,
|
||||
overlay.size.height,
|
||||
@ -40,7 +40,6 @@ Future<void> showDateFilterMenu({
|
||||
),
|
||||
title: Text(
|
||||
"Sort from newest to oldest",
|
||||
// style: context.textTheme.bodyMedium,
|
||||
style: TextStyle(
|
||||
color: isSelected == "NewestToOldest"
|
||||
? Colors.black
|
||||
@ -65,9 +64,5 @@ Future<void> showDateFilterMenu({
|
||||
),
|
||||
),
|
||||
],
|
||||
).then((value) {
|
||||
// setState(() {
|
||||
// _isDropdownOpen = false;
|
||||
// });
|
||||
});
|
||||
).then((value) {});
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ Future<void> showDeActivateFilterMenu({
|
||||
),
|
||||
title: Text(
|
||||
"Sort A to Z",
|
||||
// style: context.textTheme.bodyMedium,
|
||||
style: TextStyle(
|
||||
color: isSelected == "NewestToOldest"
|
||||
? Colors.black
|
||||
@ -65,9 +64,5 @@ Future<void> showDeActivateFilterMenu({
|
||||
),
|
||||
),
|
||||
],
|
||||
).then((value) {
|
||||
// setState(() {
|
||||
// _isDropdownOpen = false;
|
||||
// });
|
||||
});
|
||||
).then((value) {});
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ Future<void> showNameMenu({
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RelativeRect position = RelativeRect.fromRect(
|
||||
Rect.fromLTRB(
|
||||
overlay.size.width / 25,
|
||||
overlay.size.width / 35,
|
||||
240,
|
||||
0,
|
||||
overlay.size.height,
|
||||
@ -40,7 +40,6 @@ Future<void> showNameMenu({
|
||||
),
|
||||
title: Text(
|
||||
"Sort A to Z",
|
||||
// style: context.textTheme.bodyMedium,
|
||||
style: TextStyle(
|
||||
color: isSelected == "Asc" ? Colors.black : Colors.blueGrey),
|
||||
),
|
||||
@ -61,9 +60,5 @@ Future<void> showNameMenu({
|
||||
),
|
||||
),
|
||||
],
|
||||
).then((value) {
|
||||
// setState(() {
|
||||
// _isDropdownOpen = false;
|
||||
// });
|
||||
});
|
||||
).then((value) {});
|
||||
}
|
||||
|
@ -1,256 +1,59 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class DynamicTableScreen extends StatefulWidget {
|
||||
final List<String> titles;
|
||||
final List<List<Widget>> rows;
|
||||
final void Function(int columnIndex)? onFilter;
|
||||
class _HeaderColumn extends StatelessWidget {
|
||||
final String title;
|
||||
final double width;
|
||||
final bool showFilter;
|
||||
final VoidCallback? onFilter;
|
||||
final Function(double) onResize;
|
||||
|
||||
DynamicTableScreen(
|
||||
{required this.titles, required this.rows, required this.onFilter});
|
||||
|
||||
@override
|
||||
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
||||
}
|
||||
|
||||
class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
with WidgetsBindingObserver {
|
||||
late List<double> columnWidths;
|
||||
late double totalWidth;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
columnWidths = List<double>.filled(widget.titles.length, 150.0);
|
||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
super.didChangeMetrics();
|
||||
final newScreenWidth = MediaQuery.of(context).size.width;
|
||||
setState(() {
|
||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return newScreenWidth *
|
||||
0.12; // 20% of screen width for the second column
|
||||
} else if (index == 9) {
|
||||
return newScreenWidth *
|
||||
0.1; // 25% of screen width for the tenth column
|
||||
}
|
||||
return newScreenWidth *
|
||||
0.09; // Default to 10% of screen width for other columns
|
||||
});
|
||||
});
|
||||
}
|
||||
const _HeaderColumn({
|
||||
required this.title,
|
||||
required this.width,
|
||||
required this.showFilter,
|
||||
required this.onResize,
|
||||
this.onFilter,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
if (columnWidths.every((width) => width == screenWidth * 7)) {
|
||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return screenWidth * 0.11;
|
||||
} else if (index == 9) {
|
||||
return screenWidth * 0.1;
|
||||
}
|
||||
return screenWidth * 0.09;
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
clipBehavior: Clip.none,
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20))),
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.resizeColumn,
|
||||
child: GestureDetector(
|
||||
onHorizontalDragUpdate: (details) => onResize(details.delta.dx),
|
||||
child: Container(
|
||||
width: width,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(right: BorderSide(color: ColorsManager.boxDivider)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
width: totalWidth,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(15),
|
||||
topRight: Radius.circular(15))),
|
||||
child: Row(
|
||||
children: List.generate(widget.titles.length, (index) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
FittedBox(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 5, right: 5),
|
||||
width: columnWidths[index],
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Text(
|
||||
widget.titles[index],
|
||||
maxLines: 2,
|
||||
style: const TextStyle(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (index != 1 &&
|
||||
index != 9 &&
|
||||
index != 8 &&
|
||||
index != 5)
|
||||
FittedBox(
|
||||
child: IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.filterTableIcon,
|
||||
fit: BoxFit.none,
|
||||
),
|
||||
onPressed: () {
|
||||
if (widget.onFilter != null) {
|
||||
widget.onFilter!(index);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onHorizontalDragUpdate: (details) {
|
||||
setState(() {
|
||||
columnWidths[index] =
|
||||
(columnWidths[index] + details.delta.dx)
|
||||
.clamp(150.0, 300.0);
|
||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
||||
});
|
||||
},
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.resizeColumn,
|
||||
child: Container(
|
||||
color: Colors.green,
|
||||
child: Container(
|
||||
color: ColorsManager.boxDivider,
|
||||
width: 1,
|
||||
height: 50,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
widget.rows.isEmpty
|
||||
? SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 2,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
SvgPicture.asset(Assets.emptyTable),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Text(
|
||||
'No Users',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Center(
|
||||
child: Container(
|
||||
width: totalWidth,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(15),
|
||||
bottomRight: Radius.circular(15))),
|
||||
child: ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: widget.rows.length,
|
||||
itemBuilder: (context, rowIndex) {
|
||||
if (columnWidths.every((width) => width == 120.0)) {
|
||||
columnWidths = List<double>.generate(
|
||||
widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return screenWidth * 0.11;
|
||||
} else if (index == 9) {
|
||||
return screenWidth * 0.2;
|
||||
}
|
||||
return screenWidth * 0.11;
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
final row = widget.rows[rowIndex];
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 5, top: 10, right: 5, bottom: 10),
|
||||
child: Row(
|
||||
children:
|
||||
List.generate(row.length, (index) {
|
||||
return SizedBox(
|
||||
width: columnWidths[index],
|
||||
child: SizedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15, right: 10),
|
||||
child: row[index],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (rowIndex < widget.rows.length - 1)
|
||||
Row(
|
||||
children: List.generate(
|
||||
widget.titles.length, (index) {
|
||||
return SizedBox(
|
||||
width: columnWidths[index],
|
||||
child: const Divider(
|
||||
color: ColorsManager.boxDivider,
|
||||
thickness: 1,
|
||||
height: 1,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showFilter)
|
||||
IconButton(
|
||||
icon: SvgPicture.asset(Assets.filterTableIcon),
|
||||
onPressed: onFilter,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -258,3 +61,204 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TableRow extends StatelessWidget {
|
||||
final List<Widget> cells;
|
||||
final List<double> columnWidths;
|
||||
final bool isLast;
|
||||
|
||||
const _TableRow({
|
||||
required this.cells,
|
||||
required this.columnWidths,
|
||||
required this.isLast,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
for (int i = 0; i < cells.length; i++)
|
||||
Container(
|
||||
width: columnWidths[i],
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
// decoration: BoxDecoration(
|
||||
// border: Border(
|
||||
// right: BorderSide(color: ColorsManager.boxDivider),
|
||||
// ),
|
||||
// ),
|
||||
child: cells[i],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!isLast)
|
||||
Divider(
|
||||
height: 1,
|
||||
thickness: 1,
|
||||
color: ColorsManager.boxDivider,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
//===========================================================================
|
||||
|
||||
class DynamicTableScreen extends StatefulWidget {
|
||||
final List<String> titles;
|
||||
final List<List<Widget>> rows;
|
||||
final void Function(int columnIndex)? onFilter;
|
||||
|
||||
const DynamicTableScreen({
|
||||
required this.titles,
|
||||
required this.rows,
|
||||
required this.onFilter,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
||||
}
|
||||
|
||||
class _DynamicTableScreenState extends State<DynamicTableScreen> {
|
||||
late List<double> columnWidths;
|
||||
final double _minColumnWidth = 100.0;
|
||||
final double _maxColumnWidth = 300.0;
|
||||
final double _dividerWidth = 1.0;
|
||||
double _lastAvailableWidth = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
columnWidths = List.filled(widget.titles.length, _minColumnWidth);
|
||||
}
|
||||
|
||||
void _handleColumnResize(int index, double delta) {
|
||||
setState(() {
|
||||
double newWidth = columnWidths[index] + delta;
|
||||
newWidth = newWidth.clamp(_minColumnWidth, _maxColumnWidth);
|
||||
double actualDelta = newWidth - columnWidths[index];
|
||||
if (actualDelta == 0) return;
|
||||
|
||||
int nextIndex = (index + 1) % columnWidths.length;
|
||||
columnWidths[index] = newWidth;
|
||||
columnWidths[nextIndex] = (columnWidths[nextIndex] - actualDelta)
|
||||
.clamp(_minColumnWidth, _maxColumnWidth);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
return Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(15),
|
||||
topRight: Radius.circular(15),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
for (int i = 0; i < widget.titles.length; i++)
|
||||
_HeaderColumn(
|
||||
title: widget.titles[i],
|
||||
width: columnWidths[i],
|
||||
showFilter: i != 1 && i != 9 && i != 8 && i != 5,
|
||||
onFilter: () => widget.onFilter?.call(i),
|
||||
onResize: (delta) => _handleColumnResize(i, delta),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
if (widget.rows.isEmpty) {
|
||||
return SizedBox(
|
||||
height: 300,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SvgPicture.asset(Assets.emptyTable),
|
||||
const SizedBox(height: 15),
|
||||
const Text(
|
||||
'No Users',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(15),
|
||||
bottomRight: Radius.circular(15),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
for (int rowIndex = 0; rowIndex < widget.rows.length; rowIndex++)
|
||||
_TableRow(
|
||||
cells: widget.rows[rowIndex],
|
||||
columnWidths: columnWidths,
|
||||
isLast: rowIndex == widget.rows.length - 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final availableWidth = constraints.maxWidth;
|
||||
final totalDividersWidth = (widget.titles.length - 1) * _dividerWidth;
|
||||
|
||||
if (_lastAvailableWidth != availableWidth) {
|
||||
final equalWidth =
|
||||
(availableWidth - totalDividersWidth) / widget.titles.length;
|
||||
final clampedWidth =
|
||||
equalWidth.clamp(_minColumnWidth, _maxColumnWidth);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
columnWidths = List.filled(widget.titles.length, clampedWidth);
|
||||
_lastAvailableWidth = availableWidth;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
final totalTableWidth =
|
||||
columnWidths.fold(0.0, (sum, w) => sum + w) + totalDividersWidth;
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
width: totalTableWidth,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(),
|
||||
_buildBody(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ class UsersPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
Widget actionButton({required String title, required Function()? onTap}) {
|
||||
Widget actionButton(
|
||||
{bool isActive = false, required String title, Function()? onTap}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
@ -33,9 +34,11 @@ class UsersPage extends StatelessWidget {
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: title == "Delete"
|
||||
? ColorsManager.red
|
||||
: ColorsManager.spaceColor,
|
||||
color: isActive == false && title != "Delete"
|
||||
? Colors.grey
|
||||
: title == "Delete"
|
||||
? ColorsManager.red
|
||||
: ColorsManager.spaceColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
@ -108,7 +111,6 @@ class UsersPage extends StatelessWidget {
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final _blocRole = BlocProvider.of<UserTableBloc>(context);
|
||||
if (state is UsersLoadingState) {
|
||||
_blocRole.add(ChangePage(_blocRole.currentPage));
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is UsersLoadedState) {
|
||||
return Padding(
|
||||
@ -130,9 +132,12 @@ class UsersPage extends StatelessWidget {
|
||||
child: TextFormField(
|
||||
controller: searchController,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(SearchUsers(value));
|
||||
final bloc = context.read<UserTableBloc>();
|
||||
bloc.add(FilterClearEvent());
|
||||
bloc.add(SearchUsers(value));
|
||||
if (value == '') {
|
||||
bloc.add(ChangePage(1));
|
||||
}
|
||||
},
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration: textBoxDecoration(radios: 15)!.copyWith(
|
||||
@ -215,7 +220,7 @@ class UsersPage extends StatelessWidget {
|
||||
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 4,
|
||||
overlay.size.width / 5.3,
|
||||
240,
|
||||
overlay.size.width / 4,
|
||||
0,
|
||||
@ -223,8 +228,9 @@ class UsersPage extends StatelessWidget {
|
||||
list: _blocRole.jobTitle,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
isSelected: _blocRole.currentSortJopTitle,
|
||||
onOkPressed: () {
|
||||
searchController.clear();
|
||||
_blocRole.add(FilterClearEvent());
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
@ -233,14 +239,14 @@ class UsersPage extends StatelessWidget {
|
||||
Navigator.of(context).pop();
|
||||
_blocRole.add(FilterUsersByJobEvent(
|
||||
selectedJob: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder,
|
||||
sortOrder: _blocRole.currentSortJopTitle,
|
||||
));
|
||||
},
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortJopTitle = v;
|
||||
},
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortJopTitle = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -263,8 +269,9 @@ class UsersPage extends StatelessWidget {
|
||||
list: _blocRole.roleTypes,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
isSelected: _blocRole.currentSortRole,
|
||||
onOkPressed: () {
|
||||
searchController.clear();
|
||||
_blocRole.add(FilterClearEvent());
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
@ -274,13 +281,13 @@ class UsersPage extends StatelessWidget {
|
||||
context.read<UserTableBloc>().add(
|
||||
FilterUsersByRoleEvent(
|
||||
selectedRoles: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder));
|
||||
sortOrder: _blocRole.currentSortRole));
|
||||
},
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortRole = v;
|
||||
},
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortRole = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -318,8 +325,9 @@ class UsersPage extends StatelessWidget {
|
||||
list: _blocRole.createdBy,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
isSelected: _blocRole.currentSortCreatedBy,
|
||||
onOkPressed: () {
|
||||
searchController.clear();
|
||||
_blocRole.add(FilterClearEvent());
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
@ -328,13 +336,13 @@ class UsersPage extends StatelessWidget {
|
||||
Navigator.of(context).pop();
|
||||
_blocRole.add(FilterUsersByCreatedEvent(
|
||||
selectedCreatedBy: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder));
|
||||
sortOrder: _blocRole.currentSortCreatedBy));
|
||||
},
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortCreatedBy = v;
|
||||
},
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortCreatedBy = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -343,6 +351,7 @@ class UsersPage extends StatelessWidget {
|
||||
for (var item in _blocRole.status)
|
||||
item: _blocRole.selectedStatuses.contains(item),
|
||||
};
|
||||
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
@ -350,16 +359,16 @@ class UsersPage extends StatelessWidget {
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 0,
|
||||
240,
|
||||
overlay.size.width / 4,
|
||||
overlay.size.width / 5,
|
||||
0,
|
||||
),
|
||||
list: _blocRole.status,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
isSelected: _blocRole.currentSortStatus,
|
||||
onOkPressed: () {
|
||||
searchController.clear();
|
||||
_blocRole.add(FilterClearEvent());
|
||||
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
.map((entry) => entry.key)
|
||||
@ -367,13 +376,13 @@ class UsersPage extends StatelessWidget {
|
||||
Navigator.of(context).pop();
|
||||
_blocRole.add(FilterUsersByDeActevateEvent(
|
||||
selectedActivate: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder));
|
||||
sortOrder: _blocRole.currentSortStatus));
|
||||
},
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortStatus = v;
|
||||
},
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
_blocRole.currentSortStatus = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -410,7 +419,7 @@ class UsersPage extends StatelessWidget {
|
||||
return [
|
||||
Text('${user.firstName} ${user.lastName}'),
|
||||
Text(user.email),
|
||||
Text(user.jobTitle ?? '-'),
|
||||
Text(user.jobTitle),
|
||||
Text(user.roleType ?? ''),
|
||||
Text(user.createdDate ?? ''),
|
||||
Text(user.createdTime ?? ''),
|
||||
@ -427,11 +436,6 @@ class UsersPage extends StatelessWidget {
|
||||
userId: user.uuid,
|
||||
onTap: user.status != "invited"
|
||||
? () {
|
||||
// final newStatus = user.status == 'active'
|
||||
// ? 'disabled'
|
||||
// : user.status == 'disabled'
|
||||
// ? 'invited'
|
||||
// : 'active';
|
||||
context.read<UserTableBloc>().add(
|
||||
ChangeUserStatus(
|
||||
userId: user.uuid,
|
||||
@ -443,28 +447,30 @@ class UsersPage extends StatelessWidget {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
// actionButton(
|
||||
// title: "Activity Log",
|
||||
// onTap: () {},
|
||||
// ),
|
||||
actionButton(
|
||||
title: "Edit",
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return EditUserDialog(userId: user.uuid);
|
||||
},
|
||||
).then((v) {
|
||||
if (v != null) {
|
||||
if (v != null) {
|
||||
_blocRole.add(const GetUsers());
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
user.isEnabled != false
|
||||
? actionButton(
|
||||
isActive: true,
|
||||
title: "Edit",
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return EditUserDialog(
|
||||
userId: user.uuid);
|
||||
},
|
||||
).then((v) {
|
||||
if (v != null) {
|
||||
if (v != null) {
|
||||
_blocRole.add(const GetUsers());
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
)
|
||||
: actionButton(
|
||||
title: "Edit",
|
||||
),
|
||||
actionButton(
|
||||
title: "Delete",
|
||||
onTap: () {
|
||||
@ -487,9 +493,7 @@ class UsersPage extends StatelessWidget {
|
||||
},
|
||||
).then((v) {
|
||||
if (v != null) {
|
||||
if (v != null) {
|
||||
_blocRole.add(const GetUsers());
|
||||
}
|
||||
_blocRole.add(const GetUsers());
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -516,12 +520,11 @@ class UsersPage extends StatelessWidget {
|
||||
const Icon(Icons.keyboard_double_arrow_right),
|
||||
firstPageIcon:
|
||||
const Icon(Icons.keyboard_double_arrow_left),
|
||||
totalPages: (_blocRole.users.length /
|
||||
totalPages: (_blocRole.totalUsersCount.length /
|
||||
_blocRole.itemsPerPage)
|
||||
.ceil(),
|
||||
currentPage: _blocRole.currentPage,
|
||||
onPageChanged: (int pageNumber) {
|
||||
_blocRole.currentPage = pageNumber;
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(ChangePage(pageNumber));
|
||||
|
@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bl
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/users_page.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
|
||||
class RolesAndPermissionPage extends StatelessWidget {
|
||||
@ -26,11 +27,10 @@ class RolesAndPermissionPage extends StatelessWidget {
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: WebScaffold(
|
||||
enableMenuSidebar: false,
|
||||
appBarTitle: FittedBox(
|
||||
child: Text(
|
||||
'Roles & Permissions',
|
||||
style: Theme.of(context).textTheme.headlineLarge,
|
||||
),
|
||||
appBarTitle: Text(
|
||||
'Roles & Permissions',
|
||||
style:
|
||||
ResponsiveTextTheme.of(context).deviceManagementTitle,
|
||||
),
|
||||
rightBody: const NavigateHomeGridView(),
|
||||
centerBody: Row(
|
||||
|
@ -1,85 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/ac_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/one_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/three_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/two_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
|
||||
class DeviceDialogHelper {
|
||||
static Future<Map<String, dynamic>?> showDeviceDialog(
|
||||
BuildContext context,
|
||||
Map<String, dynamic> data, {
|
||||
required bool removeComparetors,
|
||||
}) async {
|
||||
final functions = data['functions'] as List<DeviceFunction>;
|
||||
|
||||
try {
|
||||
final result = await _getDialogForDeviceType(
|
||||
context,
|
||||
data['productType'],
|
||||
data,
|
||||
functions,
|
||||
removeComparetors: removeComparetors,
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>?> _getDialogForDeviceType(
|
||||
BuildContext context,
|
||||
String productType,
|
||||
Map<String, dynamic> data,
|
||||
List<DeviceFunction> functions,
|
||||
{required bool removeComparetors}) async {
|
||||
final routineBloc = context.read<RoutineBloc>();
|
||||
final deviceSelectedFunctions =
|
||||
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
||||
|
||||
switch (productType) {
|
||||
case 'AC':
|
||||
return ACHelper.showACFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
|
||||
case '1G':
|
||||
return OneGangSwitchHelper.showSwitchFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
case '2G':
|
||||
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
case '3G':
|
||||
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
|
||||
context,
|
||||
functions,
|
||||
data['device'],
|
||||
deviceSelectedFunctions,
|
||||
data['uniqueCustomId'],
|
||||
removeComparetors);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class RoutinesView extends StatefulWidget {
|
||||
const RoutinesView({super.key});
|
||||
|
||||
@override
|
||||
State<RoutinesView> createState() => _RoutinesViewState();
|
||||
}
|
||||
|
||||
class _RoutinesViewState extends State<RoutinesView> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
if (state.createRoutineView) {
|
||||
return const CreateNewRoutineView();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Create New Routines",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
RoutineViewCard(
|
||||
onTap: () {
|
||||
context.read<RoutineBloc>().add(
|
||||
(ResetRoutineState()),
|
||||
);
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
},
|
||||
icon: Icons.add,
|
||||
textString: '',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Expanded(child: FetchRoutineScenesAutomation()),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class FetchRoutineScenesAutomation extends StatefulWidget {
|
||||
const FetchRoutineScenesAutomation({super.key});
|
||||
|
||||
@override
|
||||
State<FetchRoutineScenesAutomation> createState() => _FetchRoutineScenesState();
|
||||
}
|
||||
|
||||
class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
|
||||
with HelperResponsiveLayout {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
context.read<RoutineBloc>()
|
||||
..add(const LoadScenes(spaceId, communityId))
|
||||
..add(const LoadAutomation(spaceId));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
return state.isLoading
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Scenes (Tab to Run)",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (state.scenes.isEmpty)
|
||||
Text(
|
||||
"No scenes found",
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
if (state.scenes.isNotEmpty)
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
||||
),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: state.scenes.length,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
||||
),
|
||||
child: RoutineViewCard(
|
||||
onTap: () {
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
context.read<RoutineBloc>().add(
|
||||
GetSceneDetails(
|
||||
sceneId: state.scenes[index].id,
|
||||
isTabToRun: true,
|
||||
isUpdate: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
textString: state.scenes[index].name,
|
||||
icon: state.scenes[index].icon ?? Assets.logoHorizontal,
|
||||
isFromScenes: true,
|
||||
iconInBytes: state.scenes[index].iconInBytes,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"Automations",
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
if (state.automations.isEmpty)
|
||||
Text(
|
||||
"No automations found",
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
if (state.automations.isNotEmpty)
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: isSmallScreenSize(context) ? 160 : 170,
|
||||
),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: state.automations.length,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
||||
),
|
||||
child: RoutineViewCard(
|
||||
onTap: () {
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(createRoutineView: true),
|
||||
);
|
||||
context.read<RoutineBloc>().add(
|
||||
GetAutomationDetails(
|
||||
automationId: state.automations[index].id,
|
||||
isAutomation: true,
|
||||
isUpdate: true),
|
||||
);
|
||||
},
|
||||
textString: state.automations[index].name,
|
||||
icon: state.automations[index].icon ?? Assets.automation,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
|
||||
class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
|
||||
abstract class EffectPeriodEvent extends Equatable {
|
@ -2,7 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
|
||||
part 'functions_bloc_event.dart';
|
||||
part 'functions_bloc_state.dart';
|
||||
@ -26,8 +26,7 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
||||
functionCode: event.functionData.functionCode,
|
||||
operationName: event.functionData.operationName,
|
||||
value: event.functionData.value ?? existingData.value,
|
||||
valueDescription: event.functionData.valueDescription ??
|
||||
existingData.valueDescription,
|
||||
valueDescription: event.functionData.valueDescription ?? existingData.valueDescription,
|
||||
condition: event.functionData.condition ?? existingData.condition,
|
||||
);
|
||||
} else {
|
||||
@ -59,10 +58,8 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _onSelectFunction(
|
||||
SelectFunction event, Emitter<FunctionBlocState> emit) {
|
||||
FutureOr<void> _onSelectFunction(SelectFunction event, Emitter<FunctionBlocState> emit) {
|
||||
emit(state.copyWith(
|
||||
selectedFunction: event.functionCode,
|
||||
selectedOperationName: event.operationName));
|
||||
selectedFunction: event.functionCode, selectedOperationName: event.operationName));
|
||||
}
|
||||
}
|
@ -4,12 +4,12 @@ import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/delay/delay_fucntions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/routine_details_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/delay/delay_fucntions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/routine_details_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/routine_model.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
import 'package:syncrow_web/services/routines_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
@ -19,8 +19,8 @@ import 'package:uuid/uuid.dart';
|
||||
part 'routine_event.dart';
|
||||
part 'routine_state.dart';
|
||||
|
||||
const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
const communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
String spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
String communityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9';
|
||||
|
||||
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
RoutineBloc() : super(const RoutineState()) {
|
||||
@ -57,8 +57,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false));
|
||||
add(ResetRoutineState());
|
||||
if (event.isRoutineTab) {
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,18 +156,25 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
try {
|
||||
final scenes = await SceneApi.getScenesByUnitId(event.unitId, event.communityId);
|
||||
spaceId = event.spaceId;
|
||||
communityId = event.communityId;
|
||||
|
||||
List<ScenesModel> scenes = [];
|
||||
|
||||
if (communityId.isNotEmpty && spaceId.isNotEmpty) {
|
||||
scenes = await SceneApi.getScenes(event.spaceId, event.communityId);
|
||||
}
|
||||
emit(state.copyWith(
|
||||
scenes: scenes,
|
||||
isLoading: false,
|
||||
));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
loadScenesErrorMessage: 'Failed to load scenes',
|
||||
errorMessage: '',
|
||||
loadAutomationErrorMessage: '',
|
||||
));
|
||||
isLoading: false,
|
||||
loadScenesErrorMessage: 'Failed to load scenes',
|
||||
errorMessage: '',
|
||||
loadAutomationErrorMessage: '',
|
||||
scenes: []));
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,27 +182,22 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
try {
|
||||
final automations = await SceneApi.getAutomationByUnitId(event.unitId);
|
||||
if (automations.isNotEmpty) {
|
||||
emit(state.copyWith(
|
||||
automations: automations,
|
||||
isLoading: false,
|
||||
));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
spaceId = event.spaceId;
|
||||
List<ScenesModel> automations = [];
|
||||
if (spaceId.isNotEmpty) {
|
||||
automations = await SceneApi.getAutomation(event.spaceId);
|
||||
}
|
||||
emit(state.copyWith(
|
||||
automations: automations,
|
||||
isLoading: false,
|
||||
));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
loadAutomationErrorMessage: 'Failed to load automations',
|
||||
errorMessage: '',
|
||||
loadScenesErrorMessage: '',
|
||||
));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
loadAutomationErrorMessage: 'Failed to load automations',
|
||||
errorMessage: '',
|
||||
loadScenesErrorMessage: '',
|
||||
));
|
||||
automations: []));
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,8 +292,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.createScene(createSceneModel);
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -419,8 +421,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.createAutomation(createAutomationModel);
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -785,8 +787,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
SceneApi.deleteAutomation(unitUuid: spaceId, automationId: state.automationId ?? '');
|
||||
}
|
||||
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(ResetRoutineState());
|
||||
emit(state.copyWith(isLoading: false, createRoutineView: false));
|
||||
} catch (e) {
|
||||
@ -814,7 +816,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
final devices = await DevicesManagementApi().fetchDevices();
|
||||
final devices = await DevicesManagementApi().fetchDevices('', '');
|
||||
|
||||
emit(state.copyWith(isLoading: false, devices: devices));
|
||||
} catch (e) {
|
||||
@ -892,8 +894,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -1021,8 +1023,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadAutomation(spaceId));
|
||||
add(const LoadScenes(spaceId, communityId));
|
||||
add(LoadAutomation(spaceId));
|
||||
add(LoadScenes(spaceId, communityId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
@ -27,22 +27,22 @@ class AddToThenContainer extends RoutineEvent {
|
||||
}
|
||||
|
||||
class LoadScenes extends RoutineEvent {
|
||||
final String unitId;
|
||||
final String spaceId;
|
||||
final String communityId;
|
||||
|
||||
const LoadScenes(this.unitId, this.communityId);
|
||||
const LoadScenes(this.spaceId, this.communityId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [unitId, communityId];
|
||||
List<Object> get props => [spaceId, communityId];
|
||||
}
|
||||
|
||||
class LoadAutomation extends RoutineEvent {
|
||||
final String unitId;
|
||||
final String spaceId;
|
||||
|
||||
const LoadAutomation(this.unitId);
|
||||
const LoadAutomation(this.spaceId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [unitId];
|
||||
List<Object> get props => [spaceId];
|
||||
}
|
||||
|
||||
class AddFunctionToRoutine extends RoutineEvent {
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_event.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/setting_bloc/setting_state.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/icon_model.dart';
|
||||
import 'package:syncrow_web/services/routines_api.dart';
|
||||
|
||||
class SettingBloc extends Bloc<SettingEvent, SettingState> {
|
@ -1,5 +1,5 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/icon_model.dart';
|
||||
|
||||
abstract class SettingState extends Equatable {
|
||||
const SettingState();
|
@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ac_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/three_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/two_gang_switch_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
|
||||
class DeviceDialogHelper {
|
||||
static Future<Map<String, dynamic>?> showDeviceDialog(
|
||||
BuildContext context,
|
||||
Map<String, dynamic> data, {
|
||||
required bool removeComparetors,
|
||||
}) async {
|
||||
final functions = data['functions'] as List<DeviceFunction>;
|
||||
|
||||
try {
|
||||
final result = await _getDialogForDeviceType(
|
||||
context,
|
||||
data['productType'],
|
||||
data,
|
||||
functions,
|
||||
removeComparetors: removeComparetors,
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error: $e');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>?> _getDialogForDeviceType(BuildContext context,
|
||||
String productType, Map<String, dynamic> data, List<DeviceFunction> functions,
|
||||
{required bool removeComparetors}) async {
|
||||
final routineBloc = context.read<RoutineBloc>();
|
||||
final deviceSelectedFunctions =
|
||||
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
||||
|
||||
switch (productType) {
|
||||
case 'AC':
|
||||
return ACHelper.showACFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
|
||||
case '1G':
|
||||
return OneGangSwitchHelper.showSwitchFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
case '2G':
|
||||
return TwoGangSwitchHelper.showSwitchFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
case '3G':
|
||||
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(context, functions, data['device'],
|
||||
deviceSelectedFunctions, data['uniqueCustomId'], removeComparetors);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,9 +3,9 @@ import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
@ -1,6 +1,6 @@
|
||||
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class DelayFunction extends BaseSwitchFunction {
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user