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/assets/icons/delete_space_link_icon.svg b/assets/icons/delete_space_link_icon.svg
new file mode 100644
index 00000000..a55d2e04
--- /dev/null
+++ b/assets/icons/delete_space_link_icon.svg
@@ -0,0 +1,21 @@
+
diff --git a/assets/icons/space_link_icon.svg b/assets/icons/space_link_icon.svg
new file mode 100644
index 00000000..f10c57ad
--- /dev/null
+++ b/assets/icons/space_link_icon.svg
@@ -0,0 +1,25 @@
+
diff --git a/assets/icons/success_icon.svg b/assets/icons/success_icon.svg
new file mode 100644
index 00000000..6f5dbf9e
--- /dev/null
+++ b/assets/icons/success_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/delete_space_link_icon.svg b/assets/images/delete_space_link_icon.svg
new file mode 100644
index 00000000..a55d2e04
--- /dev/null
+++ b/assets/images/delete_space_link_icon.svg
@@ -0,0 +1,21 @@
+
diff --git a/assets/images/space_link_icon.svg b/assets/images/space_link_icon.svg
new file mode 100644
index 00000000..f10c57ad
--- /dev/null
+++ b/assets/images/space_link_icon.svg
@@ -0,0 +1,25 @@
+
diff --git a/assets/images/success_icon.svg b/assets/images/success_icon.svg
new file mode 100644
index 00000000..6f5dbf9e
--- /dev/null
+++ b/assets/images/success_icon.svg
@@ -0,0 +1,3 @@
+
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/common/dialog_textfield_dropdown.dart b/lib/common/tag_dialog_textfield_dropdown.dart
similarity index 75%
rename from lib/common/dialog_textfield_dropdown.dart
rename to lib/common/tag_dialog_textfield_dropdown.dart
index ac88e5dc..219e03ce 100644
--- a/lib/common/dialog_textfield_dropdown.dart
+++ b/lib/common/tag_dialog_textfield_dropdown.dart
@@ -1,35 +1,38 @@
import 'package:flutter/material.dart';
+import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
import 'package:syncrow_web/utils/color_manager.dart';
-class DialogTextfieldDropdown extends StatefulWidget {
- final List items;
- final ValueChanged onSelected;
- final String? initialValue;
+class TagDialogTextfieldDropdown extends StatefulWidget {
+ final List items;
+ final ValueChanged onSelected;
+ final Tag? initialValue;
+ final String product;
- const DialogTextfieldDropdown({
+ const TagDialogTextfieldDropdown({
Key? key,
required this.items,
required this.onSelected,
this.initialValue,
+ required this.product,
}) : super(key: key);
@override
- _DialogTextfieldDropdownState createState() =>
- _DialogTextfieldDropdownState();
+ _DialogTextfieldDropdownState createState() => _DialogTextfieldDropdownState();
}
-class _DialogTextfieldDropdownState extends State {
+class _DialogTextfieldDropdownState extends State {
bool _isOpen = false;
OverlayEntry? _overlayEntry;
final TextEditingController _controller = TextEditingController();
final FocusNode _focusNode = FocusNode();
- List _filteredItems = [];
+ List _filteredItems = [];
@override
void initState() {
super.initState();
- _controller.text = widget.initialValue ?? '';
- _filteredItems = List.from(widget.items);
+ _controller.text = widget.initialValue?.tag ?? '';
+
+ _filterItems();
_focusNode.addListener(() {
if (!_focusNode.hasFocus) {
@@ -38,6 +41,12 @@ class _DialogTextfieldDropdownState extends State {
});
}
+ void _filterItems() {
+ setState(() {
+ _filteredItems = widget.items.where((tag) => tag.product?.uuid == widget.product).toList();
+ });
+ }
+
void _toggleDropdown() {
if (_isOpen) {
_closeDropdown();
@@ -87,7 +96,7 @@ class _DialogTextfieldDropdownState extends State {
shrinkWrap: true,
itemCount: _filteredItems.length,
itemBuilder: (context, index) {
- final item = _filteredItems[index];
+ final tag = _filteredItems[index];
return Container(
decoration: const BoxDecoration(
@@ -99,19 +108,16 @@ class _DialogTextfieldDropdownState extends State {
),
),
child: ListTile(
- title: Text(item,
+ title: Text(tag.tag ?? '',
style: Theme.of(context)
.textTheme
.bodyMedium
- ?.copyWith(
- color: ColorsManager
- .textPrimaryColor)),
+ ?.copyWith(color: ColorsManager.textPrimaryColor)),
onTap: () {
- _controller.text = item;
- widget.onSelected(item);
+ _controller.text = tag.tag ?? '';
+ widget.onSelected(tag);
setState(() {
- _filteredItems
- .remove(item); // Remove selected item
+ _filteredItems.remove(tag);
});
_closeDropdown();
},
@@ -150,11 +156,14 @@ class _DialogTextfieldDropdownState extends State {
controller: _controller,
focusNode: _focusNode,
onFieldSubmitted: (value) {
- widget.onSelected(value);
+ final selectedTag = _filteredItems.firstWhere((tag) => tag.tag == value,
+ orElse: () => Tag(tag: value));
+ widget.onSelected(selectedTag);
_closeDropdown();
},
onTapOutside: (event) {
- widget.onSelected(_controller.text);
+ widget.onSelected(_filteredItems.firstWhere((tag) => tag.tag == _controller.text,
+ orElse: () => Tag(tag: _controller.text)));
_closeDropdown();
},
style: Theme.of(context).textTheme.bodyMedium,
diff --git a/lib/common/widgets/custom_expansion_tile.dart b/lib/common/widgets/custom_expansion_tile.dart
index 8df9b663..74151ca2 100644
--- a/lib/common/widgets/custom_expansion_tile.dart
+++ b/lib/common/widgets/custom_expansion_tile.dart
@@ -56,24 +56,6 @@ class CustomExpansionTileState extends State {
children: [
Row(
children: [
- // Checkbox with independent state management
- Checkbox(
- value: false,
- onChanged: (bool? value) {
- setState(() {});
- },
- side: WidgetStateBorderSide.resolveWith((states) {
- return const BorderSide(color: ColorsManager.grayBorder);
- }),
- fillColor: WidgetStateProperty.resolveWith((states) {
- if (states.contains(WidgetState.selected)) {
- return ColorsManager.grayBorder;
- } else {
- return ColorsManager.checkBoxFillColor;
- }
- }),
- checkColor: ColorsManager.whiteColors,
- ),
// Expand/collapse icon, now wrapped in a GestureDetector for specific onTap
if (widget.children != null && widget.children!.isNotEmpty)
GestureDetector(
@@ -84,7 +66,9 @@ class CustomExpansionTileState extends State {
});
},
child: Icon(
- _isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right,
+ _isExpanded
+ ? Icons.keyboard_arrow_down
+ : Icons.keyboard_arrow_right,
color: ColorsManager.lightGrayColor,
size: 16.0, // Adjusted size for better alignment
),
@@ -101,8 +85,10 @@ class CustomExpansionTileState extends State {
_capitalizeFirstLetter(widget.title),
style: TextStyle(
color: widget.isSelected
- ? ColorsManager.blackColor // Change color to black when selected
- : ColorsManager.lightGrayColor, // Gray when not selected
+ ? ColorsManager
+ .blackColor // Change color to black when selected
+ : ColorsManager
+ .lightGrayColor, // Gray when not selected
fontWeight: FontWeight.w400,
),
),
@@ -111,9 +97,11 @@ class CustomExpansionTileState extends State {
],
),
// The expanded section (children) that shows when the tile is expanded
- if (_isExpanded && widget.children != null && widget.children!.isNotEmpty)
+ if (_isExpanded &&
+ widget.children != null &&
+ widget.children!.isNotEmpty)
Padding(
- padding: const EdgeInsets.only(left: 48.0), // Indented children
+ padding: const EdgeInsets.only(left: 24.0), // Indented children
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: widget.children!,
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..f2f640e4 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,8 +1,10 @@
+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_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 +20,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 +55,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/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart
index 4b1c37d6..562bd5b5 100644
--- a/lib/pages/access_management/bloc/access_bloc.dart
+++ b/lib/pages/access_management/bloc/access_bloc.dart
@@ -8,9 +8,6 @@ import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
-import 'package:syncrow_web/utils/constants/strings_manager.dart';
-import 'package:syncrow_web/utils/constants/temp_const.dart';
-import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
class AccessBloc extends Bloc {
diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart
index c60b4bb2..d7c7a9dd 100644
--- a/lib/pages/access_management/view/access_management.dart
+++ b/lib/pages/access_management/view/access_management.dart
@@ -3,7 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
-import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
import 'package:syncrow_web/pages/common/custom_table.dart';
@@ -18,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 {
@@ -33,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/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart
index b22dae7b..9e0ac2f9 100644
--- a/lib/pages/auth/bloc/auth_bloc.dart
+++ b/lib/pages/auth/bloc/auth_bloc.dart
@@ -15,7 +15,6 @@ import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
import 'package:syncrow_web/services/auth_api.dart';
import 'package:syncrow_web/utils/constants/strings_manager.dart';
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
-import 'package:syncrow_web/utils/navigation_service.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
class AuthBloc extends Bloc {
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