diff --git a/android/app/build.gradle b/android/app/build.gradle index 75ed15fd..8981dae5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -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" } diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..3cc77ccd --- /dev/null +++ b/android/app/google-services.json @@ -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" +} \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index 1d6d19b7..85edcfc9 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -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 } diff --git a/firebase.json b/firebase.json new file mode 100644 index 00000000..fa1105a3 --- /dev/null +++ b/firebase.json @@ -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"}}}}}} \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index dffe452f..4f245401 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -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 = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B14AB50E8716720E10D074BD /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; 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 = ""; }; /* End PBXFileReference section */ @@ -138,6 +140,7 @@ 331C8082294A63A400263BE5 /* RunnerTests */, 1454C118FFCECEEDF59152D2 /* Pods */, 20A3C64D2B1CFED5A81C3251 /* Frameworks */, + B14AB50E8716720E10D074BD /* GoogleService-Info.plist */, ); sourceTree = ""; }; @@ -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; diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..9cdebed0 --- /dev/null +++ b/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,32 @@ + + + + + API_KEY + AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw + GCM_SENDER_ID + 427332280600 + PLIST_VERSION + 1 + BUNDLE_ID + com.example.syncrowWeb + PROJECT_ID + test2-8a3d2 + STORAGE_BUCKET + test2-8a3d2.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:427332280600:ios:14346b200780dc760c7e6d + DATABASE_URL + https://test2-8a3d2-default-rtdb.firebaseio.com + + \ No newline at end of file diff --git a/lib/firebase_options_dev.dart b/lib/firebase_options_dev.dart new file mode 100644 index 00000000..93e8600c --- /dev/null +++ b/lib/firebase_options_dev.dart @@ -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', + ); +} diff --git a/lib/firebase_options_prod.dart b/lib/firebase_options_prod.dart new file mode 100644 index 00000000..485696b8 --- /dev/null +++ b/lib/firebase_options_prod.dart @@ -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', + ); +} diff --git a/lib/main.dart b/lib/main.dart index ee1a55f5..20b0311e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,11 @@ +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'; @@ -18,9 +21,13 @@ import 'package:syncrow_web/utils/theme/theme.dart'; Future main() async { try { - const environment = String.fromEnvironment('FLAVOR', defaultValue: 'development'); + const environment = + String.fromEnvironment('FLAVOR', defaultValue: 'production'); await dotenv.load(fileName: '.env.$environment'); WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp( + options: DefaultFirebaseOptionsStaging.currentPlatform, + ); initialSetup(); } catch (_) {} runApp(MyApp()); @@ -49,7 +56,8 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MultiBlocProvider( providers: [ - BlocProvider(create: (context) => HomeBloc()..add(const FetchUserInfo())), + BlocProvider( + create: (context) => HomeBloc()..add(const FetchUserInfo())), BlocProvider( create: (context) => VisitorPasswordBloc(), ), diff --git a/lib/main_dev.dart b/lib/main_dev.dart new file mode 100644 index 00000000..9d00ebf7 --- /dev/null +++ b/lib/main_dev.dart @@ -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 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( + create: (context) => VisitorPasswordBloc(), + ), + BlocProvider( + create: (context) => RoutineBloc(), + ), + BlocProvider( + 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, + )); + } +} diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index d269c824..d7c7a9dd 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -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 { @@ -32,11 +33,9 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { 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( diff --git a/lib/pages/auth/view/forget_password_page.dart b/lib/pages/auth/view/forget_password_page.dart index 0ab2c2df..5ec7e4a7 100644 --- a/lib/pages/auth/view/forget_password_page.dart +++ b/lib/pages/auth/view/forget_password_page.dart @@ -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()); } } diff --git a/lib/pages/auth/view/login_page.dart b/lib/pages/auth/view/login_page.dart index 31907c68..6f302eeb 100644 --- a/lib/pages/auth/view/login_page.dart +++ b/lib/pages/auth/view/login_page.dart @@ -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()); } } diff --git a/lib/pages/device_managment/ac/bloc/ac_bloc.dart b/lib/pages/device_managment/ac/bloc/ac_bloc.dart index 7c6ee628..7c35034e 100644 --- a/lib/pages/device_managment/ac/bloc/ac_bloc.dart +++ b/lib/pages/device_managment/ac/bloc/ac_bloc.dart @@ -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 { on(_onAcControl); on(_onAcBatchControl); on(_onFactoryReset); + on(_onAcStatusUpdated); } FutureOr _onFetchAcStatus( @@ -28,12 +30,64 @@ class AcBloc extends Bloc { 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 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 usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(ACStatusLoaded(deviceStatus)); + } + + // Future 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 _onAcControl( AcControlEvent event, Emitter emit) async { final oldValue = _getValueByCode(event.code); diff --git a/lib/pages/device_managment/ac/bloc/ac_event.dart b/lib/pages/device_managment/ac/bloc/ac_event.dart index 8d49df96..5492e198 100644 --- a/lib/pages/device_managment/ac/bloc/ac_event.dart +++ b/lib/pages/device_managment/ac/bloc/ac_event.dart @@ -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 get props => []; } +class AcUpdated extends AcsEvent {} class AcFetchDeviceStatusEvent extends AcsEvent { final String deviceId; @@ -16,7 +18,10 @@ class AcFetchDeviceStatusEvent extends AcsEvent { @override List get props => [deviceId]; } - +class AcStatusUpdated extends AcsEvent { + final AcStatusModel deviceStatus; + AcStatusUpdated(this.deviceStatus); +} class AcFetchBatchStatusEvent extends AcsEvent { final List devicesIds; diff --git a/lib/pages/device_managment/ac/view/ac_device_control.dart b/lib/pages/device_managment/ac/view/ac_device_control.dart index 5197d722..071344d7 100644 --- a/lib/pages/device_managment/ac/view/ac_device_control.dart +++ b/lib/pages/device_managment/ac/view/ac_device_control.dart @@ -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( 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: () {}, diff --git a/lib/pages/device_managment/all_devices/view/device_managment_page.dart b/lib/pages/device_managment/all_devices/view/device_managment_page.dart index 1bc4d071..81a21046 100644 --- a/lib/pages/device_managment/all_devices/view/device_managment_page.dart +++ b/lib/pages/device_managment/all_devices/view/device_managment_page.dart @@ -10,6 +10,7 @@ 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 { @@ -25,13 +26,12 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { ), ], 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(builder: (context, state) { + centerBody: + BlocBuilder(builder: (context, state) { return Row( mainAxisSize: MainAxisSize.min, children: [ @@ -48,8 +48,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, ), ), ), @@ -58,13 +61,18 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { backgroundColor: null, ), onPressed: () { - context.read().add(const TriggerSwitchTabsEvent(isRoutineTab: true)); + context + .read() + .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, ), ), ), @@ -72,7 +80,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { ); }), rightBody: const NavigateHomeGridView(), - scaffoldBody: BlocBuilder(builder: (context, state) { + scaffoldBody: + BlocBuilder(builder: (context, state) { if (state.routineTab) { return const RoutinesView(); } @@ -87,7 +96,8 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { } 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')); } diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 9297c1fe..907e5390 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -94,7 +94,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { const DeviceSearchFilters(), const SizedBox(height: 12), Container( - height: 45, + // height: 45, width: 125, decoration: containerDecoration, child: Center( diff --git a/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart b/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart index 4e13bfd6..4e8d5a8b 100644 --- a/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart +++ b/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart @@ -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 { on(_showDescription); on(_backToGridView); on(_onFactoryReset); + on(_onStatusUpdated); } void _fetchCeilingSensorStatus( CeilingInitialEvent event, Emitter 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 stream = ref.onValue; + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; - // stream.listen((DatabaseEvent event) { - // Map usersMap = event.snapshot.value as Map; - // List statusList = []; + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; - // usersMap['status'].forEach((element) { - // statusList.add(StatusModel(code: element['code'], value: element['value'])); - // }); + List 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 emit) async { + void _onStatusUpdated(StatusUpdated event, Emitter emit) { + deviceStatus = event.deviceStatus; + emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); + } + + void _changeValue( + CeilingChangeValueEvent event, Emitter emit) async { emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus)); if (event.code == 'sensitivity') { deviceStatus.sensitivity = event.value; @@ -122,7 +136,8 @@ class CeilingSensorBloc extends Bloc { 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 { }); } - FutureOr _getDeviceReports( - GetCeilingDeviceReportsEvent event, Emitter emit) async { + FutureOr _getDeviceReports(GetCeilingDeviceReportsEvent event, + Emitter emit) async { if (event.code.isEmpty) { emit(ShowCeilingDescriptionState(description: reportString)); return; @@ -155,7 +170,8 @@ class CeilingSensorBloc extends Bloc { 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 { } } - void _showDescription(ShowCeilingDescriptionEvent event, Emitter emit) { + void _showDescription( + ShowCeilingDescriptionEvent event, Emitter emit) { emit(ShowCeilingDescriptionState(description: event.description)); } - void _backToGridView(BackToCeilingGridViewEvent event, Emitter emit) { + void _backToGridView( + BackToCeilingGridViewEvent event, Emitter emit) { emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); } FutureOr _fetchCeilingSensorBatchControl( - CeilingFetchDeviceStatusEvent event, Emitter emit) async { + CeilingFetchDeviceStatusEvent event, + Emitter 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) { diff --git a/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart b/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart index 582c9836..1dc7d8d7 100644 --- a/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart +++ b/lib/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart @@ -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 get props => [devicesId, factoryResetModel]; } + + + +class StatusUpdated extends CeilingSensorEvent { + final CeilingSensorModel deviceStatus; + const StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/curtain/bloc/curtain_bloc.dart b/lib/pages/device_managment/curtain/bloc/curtain_bloc.dart index 4599f360..251d999f 100644 --- a/lib/pages/device_managment/curtain/bloc/curtain_bloc.dart +++ b/lib/pages/device_managment/curtain/bloc/curtain_bloc.dart @@ -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 { on(_onCurtainControl); on(_onCurtainBatchControl); on(_onFactoryReset); + on(_onStatusUpdated); } FutureOr _onFetchDeviceStatus( @@ -24,7 +26,7 @@ class CurtainBloc extends Bloc { 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 { } } + void _listenToChanges(String deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + final data = event.snapshot.value as Map?; + if (data == null) return; + + List 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 emit) { + emit(CurtainStatusLoading()); + deviceStatus = event.deviceStatus; + emit(CurtainStatusLoaded(deviceStatus)); + } + FutureOr _onCurtainControl( CurtainControl event, Emitter emit) async { final oldValue = deviceStatus; diff --git a/lib/pages/device_managment/curtain/bloc/curtain_event.dart b/lib/pages/device_managment/curtain/bloc/curtain_event.dart index 7236016c..dd6700f9 100644 --- a/lib/pages/device_managment/curtain/bloc/curtain_event.dart +++ b/lib/pages/device_managment/curtain/bloc/curtain_event.dart @@ -60,3 +60,7 @@ class CurtainFactoryReset extends CurtainEvent { @override List get props => [deviceId, factoryReset]; } +class StatusUpdated extends CurtainEvent { + final bool deviceStatus; + const StatusUpdated(this.deviceStatus); +} \ No newline at end of file diff --git a/lib/pages/device_managment/door_lock/bloc/door_lock_bloc.dart b/lib/pages/device_managment/door_lock/bloc/door_lock_bloc.dart index c50203f3..f83ced1a 100644 --- a/lib/pages/device_managment/door_lock/bloc/door_lock_bloc.dart +++ b/lib/pages/device_managment/door_lock/bloc/door_lock_bloc.dart @@ -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 { //on(_onDoorLockControl); on(_updateLock); on(_onFactoryReset); + on(_onStatusUpdated); + } + + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + emit(DoorLockStatusLoading()); + + deviceStatus = event.deviceStatus; + emit(DoorLockStatusLoaded(deviceStatus)); } FutureOr _onFetchDeviceStatus( @@ -28,6 +62,8 @@ class DoorLockBloc extends Bloc { await DevicesManagementApi().getDeviceStatus(event.deviceId); deviceStatus = DoorLockStatusModel.fromJson(event.deviceId, status.status); + _listenToChanges(event.deviceId); + emit(DoorLockStatusLoaded(deviceStatus)); } catch (e) { emit(DoorLockControlError(e.toString())); diff --git a/lib/pages/device_managment/door_lock/bloc/door_lock_event.dart b/lib/pages/device_managment/door_lock/bloc/door_lock_event.dart index 54fa1ddf..3f28724e 100644 --- a/lib/pages/device_managment/door_lock/bloc/door_lock_event.dart +++ b/lib/pages/device_managment/door_lock/bloc/door_lock_event.dart @@ -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 get props => [deviceId, factoryReset]; } + +class StatusUpdated extends DoorLockEvent { + final DoorLockStatusModel deviceStatus; + const StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart b/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart index 7060c668..025de303 100644 --- a/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart +++ b/lib/pages/device_managment/garage_door/bloc/garage_door_bloc.dart @@ -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 { on(_onFetchBatchStatus); on(_onFactoryReset); on(_onEditSchedule); + on(_onStatusUpdated); + } + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) async { + void _onStatusUpdated(StatusUpdated event, Emitter emit) { + deviceStatus = event.deviceStatus; + emit(GarageDoorLoadedState(status: deviceStatus)); + } + + void _fetchGarageDoorStatus( + GarageDoorInitialEvent event, Emitter 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 _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, Emitter emit) async { + Future _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, + Emitter 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 _addSchedule(AddGarageDoorScheduleEvent event, Emitter emit) async { + Future _addSchedule( + AddGarageDoorScheduleEvent event, Emitter emit) async { try { ScheduleEntry newSchedule = ScheduleEntry( category: event.category, @@ -71,9 +109,11 @@ class GarageDoorBloc extends Bloc { 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 { } } - void _onUpdateCountdownAlarm(UpdateCountdownAlarmEvent event, Emitter emit) { + void _onUpdateCountdownAlarm( + UpdateCountdownAlarmEvent event, Emitter 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 emit) { + void _onUpdateTrTimeCon( + UpdateTrTimeConEvent event, Emitter emit) { final currentState = state; if (currentState is GarageDoorLoadedState) { emit(currentState.copyWith( @@ -100,7 +143,8 @@ class GarageDoorBloc extends Bloc { } } - Future _updateSchedule(UpdateGarageDoorScheduleEvent event, Emitter emit) async { + Future _updateSchedule(UpdateGarageDoorScheduleEvent event, + Emitter emit) async { try { final updatedSchedules = deviceStatus.schedules?.map((schedule) { if (schedule.scheduleId == event.scheduleId) { @@ -127,12 +171,15 @@ class GarageDoorBloc extends Bloc { } } - Future _deleteSchedule(DeleteGarageDoorScheduleEvent event, Emitter emit) async { + Future _deleteSchedule(DeleteGarageDoorScheduleEvent event, + Emitter 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 { } } - Future _fetchSchedules(FetchGarageDoorSchedulesEvent event, Emitter emit) async { + Future _fetchSchedules(FetchGarageDoorSchedulesEvent event, + Emitter emit) async { emit(ScheduleGarageLoadingState()); try { - List schedules = - await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category); + List schedules = await DevicesManagementApi() + .getDeviceSchedules(deviceStatus.uuid, event.category); deviceStatus = deviceStatus.copyWith(schedules: schedules); emit( GarageDoorLoadedState( @@ -165,30 +213,37 @@ class GarageDoorBloc extends Bloc { } } - Future _updateSelectedTime(UpdateSelectedTimeEvent event, Emitter emit) async { + Future _updateSelectedTime( + UpdateSelectedTimeEvent event, Emitter emit) async { final currentState = state; if (currentState is GarageDoorLoadedState) { emit(currentState.copyWith(selectedTime: event.selectedTime)); } } - Future _updateSelectedDay(UpdateSelectedDayEvent event, Emitter emit) async { + Future _updateSelectedDay( + UpdateSelectedDayEvent event, Emitter emit) async { final currentState = state; if (currentState is GarageDoorLoadedState) { List 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 _updateFunctionOn(UpdateFunctionOnEvent event, Emitter emit) async { + Future _updateFunctionOn( + UpdateFunctionOnEvent event, Emitter 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 _initializeAddSchedule(InitializeAddScheduleEvent event, Emitter emit) async { + Future _initializeAddSchedule( + InitializeAddScheduleEvent event, Emitter emit) async { final currentState = state; if (currentState is GarageDoorLoadedState) { emit(currentState.copyWith( @@ -200,20 +255,25 @@ class GarageDoorBloc extends Bloc { } } - Future _fetchRecords(FetchGarageDoorRecordsEvent event, Emitter emit) async { + Future _fetchRecords( + FetchGarageDoorRecordsEvent event, Emitter 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 _onBatchControl(GarageDoorBatchControlEvent event, Emitter emit) async { + Future _onBatchControl( + GarageDoorBatchControlEvent event, Emitter emit) async { final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false; _updateLocalValue(event.code, event.value); @@ -233,11 +293,13 @@ class GarageDoorBloc extends Bloc { } } - void _backToGridView(BackToGarageDoorGridViewEvent event, Emitter emit) { + void _backToGridView( + BackToGarageDoorGridViewEvent event, Emitter emit) { emit(GarageDoorLoadedState(status: deviceStatus)); } - void _handleUpdate(GarageDoorUpdatedEvent event, Emitter emit) { + void _handleUpdate( + GarageDoorUpdatedEvent event, Emitter emit) { emit(GarageDoorLoadedState(status: deviceStatus)); } @@ -253,9 +315,11 @@ class GarageDoorBloc extends Bloc { 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 { } } - Future _onFactoryReset(GarageDoorFactoryResetEvent event, Emitter emit) async { + Future _onFactoryReset( + GarageDoorFactoryResetEvent event, Emitter 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 { } } - void _increaseDelay(IncreaseGarageDoorDelayEvent event, Emitter emit) async { + void _increaseDelay( + IncreaseGarageDoorDelayEvent event, Emitter 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 emit) async { + void _decreaseDelay( + DecreaseGarageDoorDelayEvent event, Emitter 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 emit) async { - final oldValue = event.code == 'countdown_1' ? deviceStatus.countdown1 : deviceStatus.switch1; + void _garageDoorControlEvent( + GarageDoorControlEvent event, Emitter 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 { } } - void _revertValue(String code, dynamic oldValue, Emitter emit) { + void _revertValue( + String code, dynamic oldValue, Emitter emit) { switch (code) { case 'switch_1': if (oldValue is bool) { @@ -336,7 +416,8 @@ class GarageDoorBloc extends Bloc { 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 { 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 { return super.close(); } - FutureOr _onEditSchedule(EditGarageDoorScheduleEvent event, Emitter emit) async { + FutureOr _onEditSchedule( + EditGarageDoorScheduleEvent event, Emitter emit) async { try { ScheduleEntry newSchedule = ScheduleEntry( scheduleId: event.scheduleId, @@ -410,9 +493,11 @@ class GarageDoorBloc extends Bloc { 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)); } diff --git a/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart b/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart index d1fb15bb..fc625e32 100644 --- a/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart +++ b/lib/pages/device_managment/garage_door/bloc/garage_door_event.dart @@ -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 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 get props => [deviceId, code]; @@ -232,3 +235,10 @@ class GarageDoorFactoryResetEvent extends GarageDoorEvent { @override List get props => [factoryReset, deviceId]; } + +class StatusUpdated extends GarageDoorEvent { + final GarageDoorStatusModel deviceStatus; + const StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_bloc.dart b/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_bloc.dart index 933ce28b..493e3037 100644 --- a/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_bloc.dart +++ b/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_bloc.dart @@ -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(_onFetchBatchStatus); on(_fetchReports); on(_factoryReset); + on(_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 stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(MainDoorSensorDeviceStatusLoaded(deviceStatus)); + } } diff --git a/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_event.dart b/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_event.dart index c2864333..569cfa11 100644 --- a/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_event.dart +++ b/lib/pages/device_managment/main_door_sensor/bloc/main_door_sensor_event.dart @@ -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 get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart b/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart index eb72eecd..12aeaa88 100644 --- a/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart +++ b/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_bloc.dart @@ -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 { +class OneGangGlassSwitchBloc + extends Bloc { 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(_onFetchDeviceStatus); on(_onControl); on(_onBatchControl); on(_onFetchBatchStatus); on(_onFactoryReset); + on(_onStatusUpdated); } - Future _onFetchDeviceStatus( - OneGangGlassSwitchFetchDeviceEvent event, Emitter emit) async { + Future _onFetchDeviceStatus(OneGangGlassSwitchFetchDeviceEvent event, + Emitter 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 _onControl(OneGangGlassSwitchControl event, Emitter emit) async { + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(OneGangGlassSwitchStatusLoaded(deviceStatus)); + } + + Future _onControl(OneGangGlassSwitchControl event, + Emitter emit) async { final oldValue = _getValueByCode(event.code); _updateLocalValue(event.code, event.value); @@ -52,10 +91,12 @@ class OneGangGlassSwitchBloc extends Bloc _onFactoryReset(OneGangGlassFactoryResetEvent event, Emitter emit) async { + Future _onFactoryReset(OneGangGlassFactoryResetEvent event, + Emitter 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 _onBatchControl(OneGangGlassSwitchBatchControl event, Emitter emit) async { + Future _onBatchControl(OneGangGlassSwitchBatchControl event, + Emitter emit) async { final oldValue = _getValueByCode(event.code); _updateLocalValue(event.code, event.value); @@ -83,11 +125,14 @@ class OneGangGlassSwitchBloc extends Bloc _onFetchBatchStatus( - OneGangGlassSwitchFetchBatchStatusEvent event, Emitter emit) async { + OneGangGlassSwitchFetchBatchStatusEvent event, + Emitter 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 emit) { + void _revertValueAndEmit(String deviceId, String code, bool oldValue, + Emitter emit) { _updateLocalValue(code, oldValue); emit(OneGangGlassSwitchStatusLoaded(deviceStatus)); } diff --git a/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_event.dart b/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_event.dart index 83d9b7b9..c652e31a 100644 --- a/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_event.dart +++ b/lib/pages/device_managment/one_g_glass_switch/bloc/one_gang_glass_switch_event.dart @@ -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; diff --git a/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart b/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart index 595e7e06..c2038330 100644 --- a/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart +++ b/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_bloc.dart @@ -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(_onFetchBatchStatus); on(_onBatchControl); on(_onFactoryReset); + on(_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 stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(WallLightSwitchStatusLoaded(deviceStatus)); + } + FutureOr _onControl( WallLightSwitchControl event, Emitter emit) async { final oldValue = _getValueByCode(event.code); diff --git a/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart b/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart index 5c601484..45b6e4d1 100644 --- a/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart +++ b/lib/pages/device_managment/one_gang_switch/bloc/wall_light_switch_event.dart @@ -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 get props => [deviceId, factoryReset]; } + +class StatusUpdated extends WallLightSwitchEvent { + final WallLightStatusModel deviceStatus; + StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart b/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart index 8e3c109e..174cd167 100644 --- a/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart +++ b/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_bloc.dart @@ -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 { +class ThreeGangGlassSwitchBloc + extends Bloc { ThreeGangGlassStatusModel deviceStatus; Timer? _timer; @@ -29,21 +31,57 @@ class ThreeGangGlassSwitchBloc extends Bloc(_onBatchControl); on(_onFetchBatchStatus); on(_onFactoryReset); + on(_onStatusUpdated); } - Future _onFetchDeviceStatus( - ThreeGangGlassSwitchFetchDeviceEvent event, Emitter emit) async { + Future _onFetchDeviceStatus(ThreeGangGlassSwitchFetchDeviceEvent event, + Emitter 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 _onControl(ThreeGangGlassSwitchControl event, Emitter emit) async { + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus)); + } + + Future _onControl(ThreeGangGlassSwitchControl event, + Emitter emit) async { final oldValue = _getValueByCode(event.code); _updateLocalValue(event.code, event.value); @@ -59,7 +97,8 @@ class ThreeGangGlassSwitchBloc extends Bloc _onBatchControl(ThreeGangGlassSwitchBatchControl event, Emitter emit) async { + Future _onBatchControl(ThreeGangGlassSwitchBatchControl event, + Emitter emit) async { final oldValue = _getValueByCode(event.code); _updateLocalValue(event.code, event.value); @@ -76,21 +115,26 @@ class ThreeGangGlassSwitchBloc extends Bloc _onFetchBatchStatus( - ThreeGangGlassSwitchFetchBatchStatusEvent event, Emitter emit) async { + ThreeGangGlassSwitchFetchBatchStatusEvent event, + Emitter 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 _onFactoryReset(ThreeGangGlassFactoryReset event, Emitter emit) async { + Future _onFactoryReset(ThreeGangGlassFactoryReset event, + Emitter 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 emit) { + void _revertValueAndEmit(String deviceId, String code, bool oldValue, + Emitter emit) { _updateLocalValue(code, oldValue); emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus)); } diff --git a/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_event.dart b/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_event.dart index 558b9824..82b93fba 100644 --- a/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_event.dart +++ b/lib/pages/device_managment/three_g_glass_switch/bloc/three_gang_glass_switch_event.dart @@ -49,3 +49,10 @@ class ThreeGangGlassFactoryReset extends ThreeGangGlassSwitchEvent { required this.factoryReset, }); } + +class StatusUpdated extends ThreeGangGlassSwitchEvent { + final ThreeGangGlassStatusModel deviceStatus; + StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart b/lib/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart index ca264c13..a7a03a7f 100644 --- a/lib/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart +++ b/lib/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart @@ -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 { on(_livingRoomBatchControl); on(_livingRoomFetchBatchControl); on(_livingRoomFactoryReset); + on(_onStatusUpdated); } FutureOr _onFetchDeviceStatus(LivingRoomFetchDeviceStatusEvent event, @@ -32,6 +34,7 @@ class LivingRoomBloc extends Bloc { 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 { 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 { emit(LivingRoomDeviceManagementError(e.toString())); } } + + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(LivingRoomDeviceStatusLoaded(deviceStatus)); + } } diff --git a/lib/pages/device_managment/three_gang_switch/bloc/living_room_event.dart b/lib/pages/device_managment/three_gang_switch/bloc/living_room_event.dart index c0ada0f6..d1776d52 100644 --- a/lib/pages/device_managment/three_gang_switch/bloc/living_room_event.dart +++ b/lib/pages/device_managment/three_gang_switch/bloc/living_room_event.dart @@ -58,3 +58,10 @@ class LivingRoomFactoryResetEvent extends LivingRoomEvent { @override List get props => [uuid, factoryReset]; } + +class StatusUpdated extends LivingRoomEvent { + final LivingRoomStatusModel deviceStatus; + const StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart b/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart index 5169b0e4..406821da 100644 --- a/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart +++ b/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_bloc.dart @@ -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 { TwoGangGlassStatusModel deviceStatus; Timer? _timer; - TwoGangGlassSwitchBloc({required String deviceId}) : deviceStatus = TwoGangGlassStatusModel( uuid: deviceId, @@ -28,6 +26,7 @@ class TwoGangGlassSwitchBloc on(_onBatchControl); on(_onFetchBatchStatus); on(_onFactoryReset); + on(_onStatusUpdated); } Future _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 data = + event.snapshot.value as Map; + List 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 _onControl(TwoGangGlassSwitchControl event, Emitter 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 stream = ref.onValue; + + // stream.listen((DatabaseEvent event) { + // Map usersMap = + // event.snapshot.value as Map; + + // List 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 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)); + } } diff --git a/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_event.dart b/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_event.dart index f88d61fe..02b61bd0 100644 --- a/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_event.dart +++ b/lib/pages/device_managment/two_g_glass_switch/bloc/two_gang_glass_switch_event.dart @@ -48,3 +48,11 @@ class TwoGangGlassFactoryReset extends TwoGangGlassSwitchEvent { required this.factoryReset, }); } + +class StatusUpdated extends TwoGangGlassSwitchEvent { + final TwoGangGlassStatusModel deviceStatus; + StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} + diff --git a/lib/pages/device_managment/two_g_glass_switch/view/two_gang_glass_switch_control_view.dart b/lib/pages/device_managment/two_g_glass_switch/view/two_gang_glass_switch_control_view.dart index 72f69763..cca794e9 100644 --- a/lib/pages/device_managment/two_g_glass_switch/view/two_gang_glass_switch_control_view.dart +++ b/lib/pages/device_managment/two_g_glass_switch/view/two_gang_glass_switch_control_view.dart @@ -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( - 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( + 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); diff --git a/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart b/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart index 0d35d8e8..788d8676 100644 --- a/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart +++ b/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_bloc.dart @@ -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 { on(_onFetchBatchStatus); on(_onBatchControl); on(_onFactoryReset); + on(_onStatusUpdated); } late TwoGangStatusModel deviceStatus; @@ -26,8 +28,8 @@ class TwoGangSwitchBloc extends Bloc { 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 { emit(TwoGangSwitchError(e.toString())); } } + + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(TwoGangSwitchStatusLoaded(deviceStatus)); + } } diff --git a/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart b/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart index 16973b3a..b45fd11f 100644 --- a/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart +++ b/lib/pages/device_managment/two_gang_switch/bloc/two_gang_switch_event.dart @@ -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 get props => [deviceId, factoryReset]; } + +class StatusUpdated extends TwoGangSwitchEvent { + final TwoGangStatusModel deviceStatus; + StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} diff --git a/lib/pages/device_managment/wall_sensor/bloc/wall_bloc.dart b/lib/pages/device_managment/wall_sensor/bloc/wall_bloc.dart index 41598439..a8a52fff 100644 --- a/lib/pages/device_managment/wall_sensor/bloc/wall_bloc.dart +++ b/lib/pages/device_managment/wall_sensor/bloc/wall_bloc.dart @@ -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 { 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 { // Fetch batch status FutureOr _fetchWallSensorBatchControl( - WallSensorFetchBatchStatusEvent event, Emitter emit) async { + WallSensorFetchBatchStatusEvent event, + Emitter 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 { } } - // _listenToChanges() { - // try { - // DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$deviceId'); - // Stream stream = ref.onValue; + _listenToChanges(Emitter emit) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; - // stream.listen((DatabaseEvent event) { - // Map usersMap = event.snapshot.value as Map; - // List statusList = []; + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + List 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 emit) async { + void _changeValue( + WallSensorChangeValueEvent event, Emitter emit) async { emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus)); if (event.code == 'far_detection') { deviceStatus.farDetection = event.value; @@ -125,7 +132,8 @@ class WallSensorBloc extends Bloc { 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 { 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 { } } - void _showDescription(ShowDescriptionEvent event, Emitter emit) { + void _showDescription( + ShowDescriptionEvent event, Emitter emit) { emit(WallSensorShowDescriptionState(description: event.description)); } - void _backToGridView(BackToGridViewEvent event, Emitter emit) { + void _backToGridView( + BackToGridViewEvent event, Emitter emit) { emit(WallSensorUpdateState(wallSensorModel: deviceStatus)); } diff --git a/lib/pages/device_managment/water_heater/bloc/water_heater_bloc.dart b/lib/pages/device_managment/water_heater/bloc/water_heater_bloc.dart index 498c55fb..18a0787f 100644 --- a/lib/pages/device_managment/water_heater/bloc/water_heater_bloc.dart +++ b/lib/pages/device_managment/water_heater/bloc/water_heater_bloc.dart @@ -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 { on(_onEditSchedule); on(_onDeleteSchedule); on(_onUpdateSchedule); + on(_onStatusUpdated); } late WaterHeaterStatusModel deviceStatus; @@ -78,7 +80,8 @@ class WaterHeaterBloc extends Bloc { final currentState = state as WaterHeaterDeviceStatusLoaded; final updatedDays = List.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 _updateFunctionOn( @@ -86,7 +89,8 @@ class WaterHeaterBloc extends Bloc { Emitter 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 _updateScheduleEvent( @@ -101,7 +105,8 @@ class WaterHeaterBloc extends Bloc { )); } 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 { 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 { 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 { 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 { isInchingActive: false, )); } + _listenToChanges(event.deviceId); } catch (e) { emit(WaterHeaterFailedState(error: e.toString())); } } + _listenToChanges(deviceId) { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$deviceId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(WaterHeaterDeviceStatusLoaded(deviceStatus)); + } + void _startCountdownTimer( Emitter emit, Duration countdownRemaining, @@ -334,8 +375,10 @@ class WaterHeaterBloc extends Bloc { 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 { } } - 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 { return super.close(); } - FutureOr _getSchedule(GetSchedulesEvent event, Emitter emit) async { + FutureOr _getSchedule( + GetSchedulesEvent event, Emitter emit) async { emit(ScheduleLoadingState()); try { - List schedules = - await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category); + List schedules = await DevicesManagementApi() + .getDeviceSchedules(deviceStatus.uuid, event.category); emit(WaterHeaterDeviceStatusLoaded( deviceStatus, @@ -514,7 +559,8 @@ class WaterHeaterBloc extends Bloc { // 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 { } } - FutureOr _onEditSchedule(EditWaterHeaterScheduleEvent event, Emitter emit) async { + FutureOr _onEditSchedule(EditWaterHeaterScheduleEvent event, + Emitter emit) async { if (state is WaterHeaterDeviceStatusLoaded) { final currentState = state as WaterHeaterDeviceStatusLoaded; @@ -594,11 +641,13 @@ class WaterHeaterBloc extends Bloc { // 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 { } } - FutureOr _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, Emitter emit) async { + FutureOr _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, + Emitter 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 { } } - FutureOr _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, Emitter emit) async { + FutureOr _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, + Emitter emit) async { if (state is WaterHeaterDeviceStatusLoaded) { final currentState = state as WaterHeaterDeviceStatusLoaded; diff --git a/lib/pages/device_managment/water_heater/bloc/water_heater_event.dart b/lib/pages/device_managment/water_heater/bloc/water_heater_event.dart index ff5de32c..e4cc8474 100644 --- a/lib/pages/device_managment/water_heater/bloc/water_heater_event.dart +++ b/lib/pages/device_managment/water_heater/bloc/water_heater_event.dart @@ -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 get props => [deviceStatus]; +} + + final class AddScheduleEvent extends WaterHeaterEvent { final List selectedDays; final TimeOfDay time; diff --git a/lib/pages/device_managment/water_leak/bloc/water_leak_bloc.dart b/lib/pages/device_managment/water_leak/bloc/water_leak_bloc.dart index f1063dc9..6d3ca9a6 100644 --- a/lib/pages/device_managment/water_leak/bloc/water_leak_bloc.dart +++ b/lib/pages/device_managment/water_leak/bloc/water_leak_bloc.dart @@ -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 { on(_onFetchBatchStatus); on(_onFetchWaterLeakReports); on(_onFactoryReset); + on(_onStatusUpdated); } Future _onFetchWaterLeakStatus( @@ -30,12 +32,43 @@ class WaterLeakBloc extends Bloc { 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 stream = ref.onValue; + + stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + + List 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 emit) { + deviceStatus = event.deviceStatus; + emit(WaterLeakLoadedState(deviceStatus!)); + } + Future _onControl( WaterLeakControlEvent event, Emitter emit) async { final oldValue = deviceStatus!.watersensorState; diff --git a/lib/pages/device_managment/water_leak/bloc/water_leak_event.dart b/lib/pages/device_managment/water_leak/bloc/water_leak_event.dart index 9c048280..39864462 100644 --- a/lib/pages/device_managment/water_leak/bloc/water_leak_event.dart +++ b/lib/pages/device_managment/water_leak/bloc/water_leak_event.dart @@ -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 get props => [deviceId]; } +class StatusUpdated extends WaterLeakEvent { + final WaterLeakStatusModel deviceStatus; + const StatusUpdated(this.deviceStatus); + @override + List get props => [deviceStatus]; +} + class WaterLeakControlEvent extends WaterLeakEvent { final String deviceId; final String code; diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index 04a02a11..584a6e17 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -72,8 +72,6 @@ class HomeBloc extends Bloc { emit(LoadingHome()); terms = await HomeApi().fetchTerms(); emit(HomeInitial()); - - // emit(PolicyAgreement()); } catch (e) { return; } @@ -83,7 +81,6 @@ class HomeBloc extends Bloc { try { emit(LoadingHome()); policy = await HomeApi().fetchPolicy(); - // Emit a state to trigger the UI update emit(HomeInitial()); } catch (e) { debugPrint("Error fetching policy: $e"); @@ -114,7 +111,7 @@ class HomeBloc extends Bloc { List homeItems = [ HomeItemModel( - title: 'Access', + title: 'Access Management', icon: Assets.accessIcon, active: true, onPress: (context) { @@ -134,7 +131,7 @@ class HomeBloc extends Bloc { color: ColorsManager.primaryColor, ), HomeItemModel( - title: 'Devices', + title: 'Devices Management', icon: Assets.devicesIcon, active: true, onPress: (context) { @@ -145,6 +142,7 @@ class HomeBloc extends Bloc { }, color: ColorsManager.primaryColor, ), + // HomeItemModel( // title: 'Move in', // icon: Assets.moveinIcon, diff --git a/lib/pages/roles_and_permission/view/roles_and_permission_page.dart b/lib/pages/roles_and_permission/view/roles_and_permission_page.dart index cd1cadeb..4ba83cc1 100644 --- a/lib/pages/roles_and_permission/view/roles_and_permission_page.dart +++ b/lib/pages/roles_and_permission/view/roles_and_permission_page.dart @@ -9,6 +9,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 { @@ -27,11 +28,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( diff --git a/lib/pages/spaces_management/all_spaces/view/spaces_management_page.dart b/lib/pages/spaces_management/all_spaces/view/spaces_management_page.dart index b296eca8..0a847837 100644 --- a/lib/pages/spaces_management/all_spaces/view/spaces_management_page.dart +++ b/lib/pages/spaces_management/all_spaces/view/spaces_management_page.dart @@ -13,6 +13,7 @@ import 'package:syncrow_web/pages/spaces_management/structure_selector/view/cent import 'package:syncrow_web/services/product_api.dart'; import 'package:syncrow_web/services/space_mana_api.dart'; import 'package:syncrow_web/services/space_model_mang_api.dart'; +import 'package:syncrow_web/utils/theme/responsive_text_theme.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; class SpaceManagementPage extends StatefulWidget { @@ -43,8 +44,10 @@ class SpaceManagementPageState extends State { ), ], child: WebScaffold( - appBarTitle: Text('Space Management', - style: Theme.of(context).textTheme.headlineLarge), + appBarTitle: Text( + 'Space Management', + style: ResponsiveTextTheme.of(context).deviceManagementTitle, + ), enableMenuSidebar: false, centerBody: CenterBodyWidget(), rightBody: const NavigateHomeGridView(), diff --git a/lib/utils/responsive_layout.dart b/lib/utils/responsive_layout.dart index efc1600b..c49fa0d9 100644 --- a/lib/utils/responsive_layout.dart +++ b/lib/utils/responsive_layout.dart @@ -1,18 +1,37 @@ import 'package:flutter/material.dart'; class ResponsiveLayout extends StatelessWidget { - final Widget desktopBody; final Widget mobileBody; - const ResponsiveLayout( - {super.key, required this.desktopBody, required this.mobileBody}); + final Widget? tablet; + final Widget desktopBody; + + const ResponsiveLayout({ + super.key, + required this.mobileBody, + this.tablet, + required this.desktopBody, + }); + + static bool isMobile(BuildContext context) => + MediaQuery.of(context).size.width < 650; + + static bool isTablet(BuildContext context) => + MediaQuery.of(context).size.width < 1100 && + MediaQuery.of(context).size.width >= 650; + + static bool isDesktop(BuildContext context) => + MediaQuery.of(context).size.width >= 1100; + @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { - if (constraints.maxWidth < 600) { - return mobileBody; - } else { + if (constraints.maxWidth >= 1100) { return desktopBody; + } else if (constraints.maxWidth >= 650) { + return tablet!; + } else { + return mobileBody; } }, ); diff --git a/lib/utils/theme/responsive_text_theme.dart b/lib/utils/theme/responsive_text_theme.dart new file mode 100644 index 00000000..f5daed7f --- /dev/null +++ b/lib/utils/theme/responsive_text_theme.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/responsive_layout.dart'; + +class ResponsiveTextTheme extends ThemeExtension { + final TextStyle deviceManagementTitle; + + ResponsiveTextTheme({ + required this.deviceManagementTitle, + }); + + @override + ThemeExtension copyWith() => this; + + @override + ThemeExtension lerp( + ThemeExtension? other, double t) => + this; + + static ResponsiveTextTheme of(BuildContext context) { + final isMobile = ResponsiveLayout.isMobile(context); + return Theme.of(context).extension() ?? + ResponsiveTextTheme( + deviceManagementTitle: TextStyle( + fontSize: isMobile ? 20 : 30, + fontWeight: FontWeight.w700, + color: ColorsManager.whiteColors), + ); + } +} diff --git a/lib/web_layout/web_app_bar.dart b/lib/web_layout/web_app_bar.dart index 777b0931..02b81522 100644 --- a/lib/web_layout/web_app_bar.dart +++ b/lib/web_layout/web_app_bar.dart @@ -5,10 +5,10 @@ import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; import 'package:syncrow_web/pages/home/bloc/home_state.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; -import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; +import 'package:syncrow_web/utils/responsive_layout.dart'; import 'package:syncrow_web/utils/user_drop_down_menu.dart'; -class WebAppBar extends StatefulWidget { +class WebAppBar extends StatelessWidget { final Widget? title; final Widget? centerBody; final Widget? rightBody; @@ -16,178 +16,234 @@ class WebAppBar extends StatefulWidget { const WebAppBar({super.key, this.title, this.centerBody, this.rightBody}); @override - State createState() => _WebAppBarState(); + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final user = context.read().user; + return ResponsiveLayout( + mobileBody: MobileAppBar( + title: title, + centerBody: centerBody, + rightBody: rightBody, + user: user, + ), + tablet: TabletAppBar( + title: title, + centerBody: centerBody, + rightBody: rightBody, + user: user, + ), + desktopBody: DesktopAppBar( + title: title, + centerBody: centerBody, + rightBody: rightBody, + user: user, + ), + ); + }, + ); + } } -class _WebAppBarState extends State with HelperResponsiveLayout { - @override - void initState() { - super.initState(); - } +class DesktopAppBar extends StatelessWidget { + final Widget? title; + final Widget? centerBody; + final Widget? rightBody; + final dynamic user; + + const DesktopAppBar({ + super.key, + this.title, + this.centerBody, + this.rightBody, + required this.user, + }); @override Widget build(BuildContext context) { - bool isSmallScreen = isSmallScreenSize(context); - bool isHalfMediumScreen = isHafMediumScreenSize(context); - return BlocBuilder(builder: (context, state) { - final user = context.read().user; - return Container( - height: (isSmallScreen || isHalfMediumScreen) ? 130 : 100, - decoration: const BoxDecoration(color: ColorsManager.secondaryColor), - padding: const EdgeInsets.all(10), - child: isSmallScreen || isHalfMediumScreen - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (widget.title != null) - Align( - alignment: Alignment.centerLeft, - child: widget.title!, - ), - if (widget.centerBody != null) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: widget.centerBody, - ), - if (widget.rightBody != null || user != null) - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (widget.rightBody != null) widget.rightBody!, - Row( - children: [ - SizedBox.square( - dimension: 40, - child: CircleAvatar( - backgroundColor: ColorsManager.whiteColors, - child: SizedBox.square( - dimension: 35, - child: SvgPicture.asset( - Assets.logoGrey, - fit: BoxFit.cover, - ), - ), - ), - ), - const SizedBox( - width: 10, - ), - if (user != null) - Text( - '${user.firstName} ${user.lastName}', - style: Theme.of(context).textTheme.bodyLarge, - ), - ], - ), - ], - ), - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Row( - children: [ - widget.title!, - if (widget.centerBody != null) - Padding( - padding: const EdgeInsets.only(left: 80), - child: widget.centerBody!, - ), - ], - ), + return Container( + height: 100, + decoration: const BoxDecoration(color: ColorsManager.secondaryColor), + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + children: [ + if (title != null) title!, + if (centerBody != null) + Padding( + padding: const EdgeInsets.only(left: 80), + child: centerBody!, ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.rightBody != null) - Align( - alignment: Alignment.centerRight, - child: widget.rightBody, - ), - const SizedBox( - width: 10, - ), - SizedBox.square( - dimension: 40, - child: CircleAvatar( - backgroundColor: ColorsManager.whiteColors, - child: SizedBox.square( - dimension: 35, - child: SvgPicture.asset( - Assets.logoGrey, - fit: BoxFit.cover, - ), - ), - ), - ), - const SizedBox( - width: 10, - ), - if (user != null) - Text( - '${user.firstName} ${user.lastName}', - style: Theme.of(context).textTheme.bodyLarge, - ), - const SizedBox( - width: 10, - ), - UserDropdownMenu(user: user), - // GestureDetector( - // onTap: () { - // showCustomDialog( - // context: context, - // barrierDismissible: true, - // title: 'Logout', - // message: 'Are you sure you want to logout?', - // actions: [ - // GestureDetector( - // onTap: () { - // AuthBloc.logout(); - // context.go(RoutesConst.auth); - // }, - // child: DefaultButton( - // child: Text( - // 'Ok', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith(fontSize: 12, color: Colors.white), - // ), - // ), - // ), - // const SizedBox( - // height: 10, - // ), - // GestureDetector( - // onTap: () { - // context.pop(); - // }, - // child: DefaultButton( - // child: Text( - // 'Cancel', - // style: Theme.of(context) - // .textTheme - // .bodyMedium! - // .copyWith(fontSize: 12, color: Colors.white), - // ), - // ), - // ), - // ], - // ); - // }, - // child: const Icon( - // Icons.logout, - // color: ColorsManager.whiteColors, - // ), - // ) - ], - ), - ], - ), - ); - }); + ], + ), + ), + _buildUserSection(context), + ], + ), + ); + } + + Widget _buildUserSection(BuildContext context) { + return Row( + children: [ + if (rightBody != null) rightBody!, + const SizedBox(width: 24), + _UserAvatar(), + const SizedBox(width: 12), + if (user != null) + Text( + '${user.firstName} ${user.lastName}', + style: Theme.of(context).textTheme.bodyLarge, + ), + const SizedBox(width: 12), + UserDropdownMenu(user: user), + ], + ); + } +} + +class TabletAppBar extends StatelessWidget { + final Widget? title; + final Widget? centerBody; + final Widget? rightBody; + final dynamic user; + + const TabletAppBar({ + super.key, + this.title, + this.centerBody, + this.rightBody, + required this.user, + }); + + @override + Widget build(BuildContext context) { + return Container( + height: 100, + decoration: const BoxDecoration(color: ColorsManager.secondaryColor), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (title != null) Expanded(child: title!), + _buildUserSection(context), + ], + ), + if (centerBody != null) Expanded(child: centerBody!), + ], + ), + ); + } + + Widget _buildUserSection(BuildContext context) { + return Row( + children: [ + if (rightBody != null) rightBody!, + const SizedBox(width: 16), + _UserAvatar(), + if (user != null) ...[ + const SizedBox(width: 8), + Text( + '${user.firstName} ${user.lastName}', + style: + Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 14), + ), + ], + UserDropdownMenu(user: user), + ], + ); + } +} + +class MobileAppBar extends StatelessWidget { + final Widget? title; + final Widget? centerBody; + final Widget? rightBody; + final dynamic user; + + const MobileAppBar({ + super.key, + this.title, + this.centerBody, + this.rightBody, + required this.user, + }); + + @override + Widget build(BuildContext context) { + return Container( + height: 135, + decoration: const BoxDecoration(color: ColorsManager.secondaryColor), + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (title != null) title!, + _buildUserSection(context), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (centerBody != null) + Padding( + padding: const EdgeInsets.only(top: 8), + child: centerBody!, + ), + if (rightBody != null) + Padding( + padding: const EdgeInsets.only(top: 8), + child: rightBody!, + ), + ], + ), + ], + ), + ); + } + + Widget _buildUserSection(BuildContext context) { + return Row( + children: [ + _UserAvatar(), + if (user != null) ...[ + const SizedBox(width: 8), + Text( + '${user.firstName} ${user.lastName}', + style: + Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 14), + ), + ], + UserDropdownMenu(user: user), + ], + ); + } +} + +class _UserAvatar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SizedBox.square( + dimension: 40, + child: CircleAvatar( + backgroundColor: ColorsManager.whiteColors, + child: SizedBox.square( + dimension: 35, + child: SvgPicture.asset( + Assets.logoGrey, + fit: BoxFit.cover, + ), + ), + ), + ); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 51aae316..e6f3527d 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,20 @@ import FlutterMacOS import Foundation +import firebase_analytics +import firebase_core +import firebase_crashlytics +import firebase_database import flutter_secure_storage_macos import path_provider_foundation import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin")) + FLTFirebaseDatabasePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseDatabasePlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index eec16af6..7bfb45ff 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ /* Begin PBXBuildFile section */ 108157F896CD9F637B06D7C0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DAF1C60594A51D692304366 /* Pods_Runner.framework */; }; + 2901225E5FAB0C696EE79F77 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 996A2A515D007C9FED5396A5 /* GoogleService-Info.plist */; }; 2D0F1F294F673EF0DB5E4CA1 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E148CBDFFE42BF88E8C34DE0 /* Pods_RunnerTests.framework */; }; 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; @@ -84,6 +85,7 @@ 81F2F315AC5109F6F5D27BE6 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 96C46007EE0A4E9E1D6D74CE /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 996A2A515D007C9FED5396A5 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; A604E311B663FBF4B7C54DC5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; AB949539E0D0A8E2BDAB9ADF /* 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 = ""; }; E148CBDFFE42BF88E8C34DE0 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -138,6 +140,7 @@ 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, 75DCDFECC7757C5159E8F0C5 /* Pods */, + 996A2A515D007C9FED5396A5 /* GoogleService-Info.plist */, ); sourceTree = ""; }; @@ -241,6 +244,7 @@ 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, 92D754792F50A5D35F6D5AEE /* [CP] Embed Pods Frameworks */, + 7E188D2155D07A3E9E027C0F /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, ); buildRules = ( ); @@ -317,6 +321,7 @@ files = ( 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + 2901225E5FAB0C696EE79F77 /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -361,6 +366,24 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 7E188D2155D07A3E9E027C0F /* 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=macos --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"; + }; 8ECFD939A4D371A145DBA191 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/macos/Runner/GoogleService-Info.plist b/macos/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..9cdebed0 --- /dev/null +++ b/macos/Runner/GoogleService-Info.plist @@ -0,0 +1,32 @@ + + + + + API_KEY + AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw + GCM_SENDER_ID + 427332280600 + PLIST_VERSION + 1 + BUNDLE_ID + com.example.syncrowWeb + PROJECT_ID + test2-8a3d2 + STORAGE_BUCKET + test2-8a3d2.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:427332280600:ios:14346b200780dc760c7e6d + DATABASE_URL + https://test2-8a3d2-default-rtdb.firebaseio.com + + \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 7833f1ec..a0cbfaad 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: e051259913915ea5bc8fe18664596bea08592fd123930605d562969cd7315fcd + url: "https://pub.dev" + source: hosted + version: "1.3.51" args: dependency: transitive description: @@ -153,6 +161,94 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + sha256: "47428047a0778f72af53a3c7cb5d556e1cb25e2327cc8aa40d544971dc6245b2" + url: "https://pub.dev" + source: hosted + version: "11.4.2" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + sha256: "1076f4b041f76143e14878c70f0758f17fe5910c0cd992db9e93bd3c3584512b" + url: "https://pub.dev" + source: hosted + version: "4.3.2" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + sha256: "8f6dd64ea6d28b7f5b9e739d183a9e1c7f17027794a3e9aba1879621d42426ef" + url: "https://pub.dev" + source: hosted + version: "0.5.10+8" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "93dc4dd12f9b02c5767f235307f609e61ed9211047132d07f9e02c668f0bfc33" + url: "https://pub.dev" + source: hosted + version: "3.11.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf + url: "https://pub.dev" + source: hosted + version: "5.4.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0e13c80f0de8acaa5d0519cbe23c8b4cc138a2d5d508b5755c861bdfc9762678" + url: "https://pub.dev" + source: hosted + version: "2.20.0" + firebase_crashlytics: + dependency: "direct main" + description: + name: firebase_crashlytics + sha256: "6273ed71bcd8a6fb4d0ca13d3abddbb3301796807efaad8782b5f90156f26f03" + url: "https://pub.dev" + source: hosted + version: "4.3.2" + firebase_crashlytics_platform_interface: + dependency: transitive + description: + name: firebase_crashlytics_platform_interface + sha256: "94f3986e1a10e5a883f2ad5e3d719aef98a8a0f9a49357f6e45b7d3696ea6a97" + url: "https://pub.dev" + source: hosted + version: "3.8.2" + firebase_database: + dependency: "direct main" + description: + name: firebase_database + sha256: cd2354dfef68e52c0713b5efbb7f4e10dfc2aff2f945c7bc8db34d1934170627 + url: "https://pub.dev" + source: hosted + version: "11.3.2" + firebase_database_platform_interface: + dependency: transitive + description: + name: firebase_database_platform_interface + sha256: d430983f4d877c9f72f88b3d715cca9a50021dd7ccd8e3ae6fb79603853317de + url: "https://pub.dev" + source: hosted + version: "0.2.6+2" + firebase_database_web: + dependency: transitive + description: + name: firebase_database_web + sha256: f64edae62c5beaa08e9e611a0736d64ab11a812983a0aa132695d2d191311ea7 + url: "https://pub.dev" + source: hosted + version: "0.2.6+8" fixnum: dependency: transitive description: @@ -572,10 +668,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "3a293170d4d9403c3254ee05b84e62e8a9b3c5808ebd17de6a33fe9ea6457936" + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: @@ -777,10 +873,10 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.1.0" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f4108d5c..fd7ed797 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -56,6 +56,11 @@ dependencies: number_pagination: ^1.1.6 url_launcher: ^6.2.5 flutter_html: ^3.0.0-beta.2 + firebase_analytics: ^11.4.0 + firebase_core: ^3.11.0 + firebase_crashlytics: ^4.3.2 + firebase_database: ^11.3.2 + dev_dependencies: flutter_test: diff --git a/web/index.html b/web/index.html index a8b2aa25..d099103c 100644 --- a/web/index.html +++ b/web/index.html @@ -40,6 +40,8 @@ + + diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 2048c455..0e0afee0 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,10 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index de626cc8..9efea82a 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + firebase_core flutter_secure_storage_windows url_launcher_windows )