diff --git a/README.md b/README.md
index 451d649a..afb0d21f 100644
--- a/README.md
+++ b/README.md
@@ -1,132 +1,64 @@
-# get-flutter-fire
-
-This codebase provides a boilerplate code utilizing the following three technologies:
-
-1. Flutter 3.0 - For UX and uses Dart languange. See [https://flutter.dev/]
-2. GetX - State management for Flutter. See [https://github.com/jonataslaw/getx/tree/4.6.1]
-3. Firebase - For Backend as a Service. See [https://firebase.google.com/]
- 1. Easy Authentication flow
- 2. Server side functions
- 3. Remote Configurations which can be used for A/B testing
-
-This was created as part of my own learning process and you will find that git commits were made according to the Steps listed below. You can use the git version history to check each commit and learn step by step, as I did.
-
-I am also using this codebase as an experiment towards hiring people (freshers especially but not limited to them) for my development team. If you are in Mumbai and are interested to join my team, you can use this codebase in the following manner:
-
-* Fork the codebase
-* Add your own firebase_options.dart (follow steps and see firebase_options.template)
-* **Build your own application using this as a base (integrating any existing project of yours also works)**, or complete a TODO or fix a bug (only if you have no other ideas)
-* Send me a Pull Request. Mention a way of connecting with you in the commit message along with details of commit. Also modify ReadMe to say what you have changed in detail.
-* I will go through the request and then connect with you if I find the entry to be interesting and take an interview round.
-
-## The Steps
-
-Step 1: Use Get CLI [https://pub.dev/packages/get_cli]
-
-`get create project`
-
-Step 2: Copy code from [https://github.com/jonataslaw/getx/tree/4.6.1/example_nav2/lib]
-
-Step 3: Integrate FlutterFire Authentication
-
-- Tutorials [https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps#0] for inspiration
-- Firebase Documentation [https://firebase.google.com/docs/auth/flutter/start]
-- Blog [www.medium.com/TBD]
-- To compile the code ensure that you generate your own firebase_options.dart by running
-
- `flutterfire configure`
-
-Step 4: Add Google OAuth [https://firebase.google.com/codelabs/firebase-auth-in-flutter-apps#6]. Note ensure you do the steps for Android and iOS as the code for it is not in Github
-
-Step 5: Add Guest User/Anonymous login with a Cart and Checkout use case [https://firebase.google.com/docs/auth/flutter/anonymous-auth]
-
-* delete unlinked anonymous user post logout
-
-Step 6: Add ImagePicker and Firebase Storage for profile image
-
-* Create PopupMenu button for web [https://api.flutter.dev/flutter/material/PopupMenuButton-class.html]
-* BottomSheet for phones and single file button for desktops
-* GetX and Image Picker [https://stackoverflow.com/questions/66559553/flutter-imagepicker-with-getx]
-* Add FilePicker [https://medium.com/@onuaugustine07/pick-any-file-file-picker-flutter-f82c0144e27c]
-* Firebase Storage [https://mercyjemosop.medium.com/select-and-upload-images-to-firebase-storage-flutter-6fac855970a9] and [https://firebase.google.com/docs/storage/flutter/start]
-
- Modify the Firebase Rules
- `service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow write: if request.auth.uid != null; allow read: if true; } } }`
-
- Fix CORS [https://stackoverflow.com/questions/37760695/firebase-storage-and-access-control-allow-origin]
-* PList additions [https://medium.com/unitechie/flutter-tutorial-image-picker-from-camera-gallery-c27af5490b74]
-
-Step 7: Additional Auth flow items
-
-1. Add a Change Password Screen. The Flutter Fire package does not have this screen.
-2. TODO: Add ReCaptcha to login flow for password authentication for Web only
- * Phone Auth on Web has a ReCaptcha already [https://firebase.flutter.dev/docs/auth/phone/]. Tried to use that library but it is very cryptic.
- * Use the following instead [https://stackoverflow.com/questions/60675575/how-to-implement-recaptcha-into-a-flutter-app] or [https://medium.com/cloudcraftz/securing-your-flutter-web-app-with-google-recaptcha-b556c567f409] or [https://pub.dev/packages/g_recaptcha_v3]
-3. TODO: Ensure Reset Password has Email verification
-4. TODO: Add Phone verification [https://firebase.google.com/docs/auth/flutter/phone-auth]
- * See [https://github.com/firebase/flutterfire/issues/4189].
-5. TODO: Add 2FA with SMS Pin. This screen is available in the Flutter Fire package
-
-Step 8: Add Firebase Emulator to test on laptop instead of server so that we can use Functions without upgrading the plan to Blaze. See [https://firebase.google.com/docs/emulator-suite/install_and_configure]
-
-Step 9: Add User Roles using Custom Claims. This requires upgrade of plan as we need to use Firebase Functions. Instead using Emulator.
-
-1. In Emulator we can add user via http://127.0.0.1:4000/auth and add custom claim via UI as {"role":"admin"}. The effect is shown via Product page in Nav instead of Cart page for admin user.
-2. Add Function to add the custom claim to make the first user the admin using the Admin SDK
-3. Registeration form to collect some data post signUp and enforce email verification from Client side.
-
- * Note! for Emulator check the console to verify using the link provided as email is not sent.
-4. Enforcing verify email using a button which appears when SignIn fails due to non verification.
-
- * Fixed the error handling message during login.
- * Coverted server side to Typescript
- * Enabled Resend verification mail button
- * Approach 1 - Use Email Link Authentication and signIn, assuming it marks email as verified also. We cannot send the verification mail as is, since that can be sent only if signed in (which was allowed only for first login post signup)
- * Refer https://firebase.google.com/docs/auth/flutter/email-link-auth
- * TODO Enable Deep Linking: According to https://firebase.google.com/docs/dynamic-links/flutter/receive, the Flutter feature is being deprecated and we should use the AppLinks (Android), UniversalLinks(iOS) instead. Leaving this for future as adding complexity.
- * We could use the server side handling instead of deep linking. See [https://firebase.google.com/docs/auth/custom-email-handler?hl=en&authuser=0#web]. However, this requires changing the email template for the URL which is not possible in Emulator. Using the continueURL instead does not work as oobCode is already expired. This handling also uses the web client sdk. Thus it is better to go with the below method instead.
- * Approach 2 - (Hack) send a create request with suffix ".verify" added in email when button clicked. Use the server side beforeCreate to catch this and send verification mail
- * Note that the Server side beforeCreate function can also bypass user creation till verification but the user record (esp password) needs to be stored anyways, so bypassing user creation is not a good idea. Instead, we should use the verified tag in subsequent processing
- * Sending emails from server side is possible but by using the web client SDK.
-5. TODO: Other Items
-
- * TODO: Using autocomplete for emails is throwing error log in terminal. No impact but need to fix when all is done.
- * TODO: Add a job that removes all unverified users after a while automatically. This could be useful if you were victim of bot attacks, but adding the Recaptcha is better precaution. See [https://stackoverflow.com/questions/67148672/how-to-delete-unverified-e-mail-addresses-in-firebase-authentication-flutter/67150606#67150606]
-6. Added Roles of Buyer and Seller.
-
- 1. Added Access level in increasing order of role order => Buyer then Seller then Admin
- 2. Created Navigation for each of Admin, Buyer, Seller screens
- 3. Allowed switch from lower role Navigation to Navigation view till the given role of the user
-
-Step 10: Firebase Remote Config for A/B testing. See [https://firebase.google.com/docs/remote-config]
-
-1. Complete the Screen enum based Navigation framework
-2. Config useBottomSheetForProfileOptions for Navigation element to be one of the following
- * False: Drawer for Account, Settings, Sign Out
- * True: Hamburger that opens BottomSheet (Context Menu in larger screen) for the same options
-3. TODO: Config for adding Search Bar at the Top vs a Bottom Navigation button
-
-Step 11: TODO: CRUD
-
-* Users request role upgrade
-* Add this request data to Firebase Datastore
-* Create ListView with slidable tiles for approvals
-* Admin SDK used by admin user via workflow on this request data and is approved from app
- * Allow a Plan attribute via Custome Claims (e.g. Premium user flag) for Buyer and Seller, to add features which are not Navigation linked. Add a button Upgrade to Plan in Drawer that leads to Payment screen. Also certain aspects of premium plan can be visible that leads to upgrade plan screen via middleware
-* Nested Category, Sub-Category tree creation
-
-Step 12: TODO: Theming and Custom Settings
-
-* Add Persona (like that in Netflix) and create a Persona selection only for Buyer Role
-* Add Minimal (Three Color Gradient Pallette) Material Theme. Align it with Persona Templates (like Kids Template in Netflix)
-* Dark theme toggle setting based on each Persona of the logged in User
-
-Step 13: TODO: Large vs Small screen responsiveness
-
-* Drawer: Triggered by Top Left Icon (App Logo). For iOS this icon changes to back button when required. Contains allowed Role List, Screens specified as Drawer. Becomes Left Side Navigation for Horizontal Screens. Can have additional extreme left vertical Navigation Strip. Bottom Navigation Bar also folds into this strip in Horizontal Screens.
-* Top Right Icon: used for Login and post Login triggers BottomSheet/Context Menu for Persona Change, Profile, Settings, Change Password, Logout
-* Search Bar (Toggle Button for phones) on Top Center with Title
-* Status Bottom Bar for desktops only instead of SnackBars
-* FAB vs Main Menu
-
-Step 14: TODO: Make own login flow screens. Remove firebase library reference from all but auth_service
+## Sharekhan Qualification Project (README.md)
+
+**Welcome!** This repository holds the code for my Sharekhan qualification project, built using Flutter 3.0.
+
+This README provides an overview of:
+
+* Technologies used
+* Key features implemented
+* Setup and running instructions
+* My contributions
+
+**Technologies Used:**
+
+* **Flutter 3.0:** A powerful toolkit for building beautiful native apps for mobile, web, and desktop from a single codebase using Dart.
+* **GetX:** A comprehensive state management solution for Flutter, providing reactive programming, route management, and dependency injection.
+* **Firebase:** A suite of cloud-based tools for building and managing applications, including authentication, cloud functions, and real-time databases.
+
+**Key Features:**
+
+1. **Firebase Initialization:**
+ - Configured for macOS, iOS, and web platforms (lib/main.dart).
+ - Ensures Firebase services are accessible throughout the app.
+2. **New Features:**
+ * **Change Password Screen:** (lib/screens/auth/change_password_screen.dart)
+ - Manages changing user passwords with GetX for reactive UI updates.
+ * **ReCaptcha Integration for Web:** (lib/controllers/recaptcha_controller.dart)
+ - Simulates ReCaptcha verification (actual API integration required).
+ * **Email Verification for Password Reset:** (lib/controllers/reset_password_controller.dart)
+ - Manages password reset with email verification and GetX notifications.
+ * **Phone Authentication and 2FA with SMS Pin:** (lib/controllers/auth_controller.dart)
+ - Handles phone authentication and two-factor authentication (2FA) with SMS.
+ * **Large vs Small Screen Responsiveness:** (lib/screens/responsive_layout.dart)
+ - ResponsiveLayout widget adapts the UI based on screen size for optimal user experience.
+3. **Modified Existing Files:**
+ * **Login Screen:** (lib/screens/auth/login_screen.dart)
+ - Updated to integrate ReCaptcha verification with dynamic UI updates via GetX.
+ * **Reset Password Screen:** (lib/screens/auth/reset_password_screen.dart)
+ - Provides UI with fields, buttons, and GetX-based state management.
+ * **Phone Authentication Screen:** (lib/screens/auth/phone_auth_screen.dart)
+ - Added UI for phone number and SMS code with GetX for updates and notifications.
+ * **Custom Claims for User Roles:** (lib/services/role_service.dart)
+ - RoleService class interacts with Firebase Cloud Functions to set user roles.
+ * **Role Management Screen:** (lib/screens/admin/role_management_screen.dart)
+ - UI for managing roles with RoleService for updates and GetX notifications.
+ * **Theming and Responsiveness:** (lib/main.dart)
+ - Sets up theming (light/dark) and responsive HomeScreen for different devices.
+
+**How to Run:**
+
+1. Install dependencies: `flutter pub get`
+2. Setup Firebase: Add configuration files to `android/app/` and `ios/Runner/`.
+3. Run the app: `flutter run` on your device or emulator.
+
+**About My Contributions:**
+
+This project marks my initial venture into Flutter and mobile development. Having expertise in Python's AI and Machine Learning, transitioning to mobile development has been a challenging yet rewarding experience. I'm eager to further develop my skills in this area.
+
+**Contact:**
+
+* Name: Parth Dhabalia
+* PRN: 1032211410
+* College: MIT WPU, PUNE
+* Email: parthdhabalia07@gmail.com
+* Phone: 9518339401
\ No newline at end of file
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 72b295f6..aab7b021 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,7 +1,7 @@
-analyzer:
- errors:
- constant_identifier_names: ignore
-include: package:flutter_lints/flutter.yaml
-linter:
- rules:
-
+analyzer:
+ errors:
+ constant_identifier_names: ignore
+include: package:flutter_lints/flutter.yaml
+linter:
+ rules:
+
diff --git a/android/app/google_services.json b/android/app/google_services.json
new file mode 100644
index 00000000..ed2e53b5
--- /dev/null
+++ b/android/app/google_services.json
@@ -0,0 +1,29 @@
+{
+ "project_info": {
+ "project_number": "1071039837988",
+ "project_id": "getflutterfire-96270",
+ "storage_bucket": "getflutterfire-96270.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:1071039837988:android:d76cc4d69414936bebe5b1",
+ "android_client_info": {
+ "package_name": "com.example.get_flutter_fire"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyDKVYA-7ISM9N5XLdW7DXvydslx5iT86lM"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt b/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt
new file mode 100644
index 00000000..79c3f053
--- /dev/null
+++ b/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.example.get_flutter_fire
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 7c569640..e041d382 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -1,26 +1,26 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- App
- CFBundleIdentifier
- io.flutter.flutter.app
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- App
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
- CFBundleVersion
- 1.0
- MinimumOSVersion
- 12.0
-
-
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ 12.0
+
+
diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist
new file mode 100644
index 00000000..08d99212
--- /dev/null
+++ b/ios/Runner/GoogleService-Info.plist
@@ -0,0 +1,30 @@
+
+
+
+
+ API_KEY
+ AIzaSyBlUH4VwVkOC_7Y9-yuvw1zEtubm6Oktqw
+ GCM_SENDER_ID
+ 1071039837988
+ PLIST_VERSION
+ 1
+ BUNDLE_ID
+ com.example.getFlutterFire
+ PROJECT_ID
+ getflutterfire-96270
+ STORAGE_BUCKET
+ getflutterfire-96270.appspot.com
+ IS_ADS_ENABLED
+
+ IS_ANALYTICS_ENABLED
+
+ IS_APPINVITE_ENABLED
+
+ IS_GCM_ENABLED
+
+ IS_SIGNIN_ENABLED
+
+ GOOGLE_APP_ID
+ 1:1071039837988:ios:b1c27875360f68a0ebe5b1
+
+
\ No newline at end of file
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index fc7f1dd4..acdaa70b 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -1,55 +1,55 @@
-
-
-
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- Get Flutter Fire
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- get_flutter_fire
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- $(FLUTTER_BUILD_NAME)
- CFBundleSignature
- ????
- CFBundleVersion
- $(FLUTTER_BUILD_NUMBER)
- LSRequiresIPhoneOS
-
- UILaunchStoryboardName
- LaunchScreen
- UIMainStoryboardFile
- Main
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UISupportedInterfaceOrientations~ipad
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- CADisableMinimumFrameDurationOnPhone
-
- UIApplicationSupportsIndirectInputEvents
-
- NSCameraUsageDescription
- Allow access to camera
- NSMicrophoneUsageDescription
- Allow access to microphone for video recording
- NSPhotoLibraryUsageDescription
- Allow access to photo library
-
-
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Get Flutter Fire
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ get_flutter_fire
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSupportsIndirectInputEvents
+
+ NSCameraUsageDescription
+ Allow access to camera
+ NSMicrophoneUsageDescription
+ Allow access to microphone for video recording
+ NSPhotoLibraryUsageDescription
+ Allow access to photo library
+
+
diff --git a/lib/app/middleware/auth_middleware.dart b/lib/app/middleware/auth_middleware.dart
index 827dd96c..8d602385 100644
--- a/lib/app/middleware/auth_middleware.dart
+++ b/lib/app/middleware/auth_middleware.dart
@@ -1,94 +1,94 @@
-// ignore_for_file: avoid_print
-import 'package:get/get.dart';
-import 'package:get_flutter_fire/models/role.dart';
-import 'package:get_flutter_fire/services/auth_service.dart';
-import 'package:get_flutter_fire/app/routes/app_pages.dart';
-
-Future loginVerify(bool check, GetNavConfig route,
- Future Function(GetNavConfig) redirector) async {
- final newRoute = route.location == Routes.LOGIN
- ? Routes.LOGIN
- : Routes.LOGIN_THEN(route.location);
- if (check) {
- return GetNavConfig.fromRoute(newRoute);
- }
-
- // Below could be used if the login was happening without verification.
- // This will never get reached if server is sending error in login due to non verification
- // With customClaims status == "creating", it will reach here for SignUp case only
- if (!AuthService.to.isEmailVerified && !AuthService.to.registered.value) {
- return GetNavConfig.fromRoute(route.location == Routes.REGISTER
- ? Routes.REGISTER
- : Routes.REGISTER_THEN(route.location));
- }
-
- return await redirector(route);
-}
-
-// class EnsureAuthMiddleware extends GetMiddleware {
-// @override
-// Future redirectDelegate(GetNavConfig route) async {
-// // you can do whatever you want here
-// // but it's preferable to make this method fast
-
-// return await loginVerify(
-// !AuthService.to.isLoggedInValue, route, super.redirectDelegate);
-// }
-// }
-
-class EnsureNotAuthedOrGuestMiddleware extends GetMiddleware {
- //AccessLevel.notAuthed
- @override
- Future redirectDelegate(GetNavConfig route) async {
- if (AuthService.to.isLoggedInValue && !AuthService.to.isAnon) {
- //NEVER navigate to auth screen, when user is already authed
- return GetNavConfig.fromRoute(
- AuthService.to.registered.value ? Routes.HOME : Routes.REGISTER);
- }
- return await super.redirectDelegate(route);
- }
-}
-
-class EnsureAuthedAndNotGuestMiddleware extends GetMiddleware {
- //AccessLevel.authenticated
- @override
- Future redirectDelegate(GetNavConfig route) async {
- return await loginVerify(
- !AuthService.to.isLoggedInValue || AuthService.to.isAnon,
- route,
- super.redirectDelegate);
- }
-}
-
-class EnsureRoleMiddleware extends GetMiddleware {
- //AccessLevel.roleBased
- Role role;
- EnsureRoleMiddleware(this.role);
-
- @override
- Future redirectDelegate(GetNavConfig route) async {
- if (!AuthService.to.isLoggedInValue || !AuthService.to.hasRole(role)) {
- final newRoute = Routes.LOGIN_THEN(route.location);
- return GetNavConfig.fromRoute(newRoute);
- }
- return await super.redirectDelegate(route);
- }
-}
-
-class EnsureAuthOrGuestMiddleware extends GetMiddleware {
- //AccessLevel.guest
- @override
- Future redirectDelegate(GetNavConfig route) async {
- // you can do whatever you want here
- // but it's preferable to make this method fast
- // In this case this is taking human input and is not fast
-
- if (!AuthService.to.isLoggedInValue) {
- bool? value = await AuthService.to.guest();
- if (value != true) {
- return GetNavConfig.fromRoute(Routes.LOGIN);
- }
- }
- return await super.redirectDelegate(route);
- }
-}
+// ignore_for_file: avoid_print
+import 'package:get/get.dart';
+import 'package:get_flutter_fire/models/role.dart';
+import 'package:get_flutter_fire/services/auth_service.dart';
+import 'package:get_flutter_fire/app/routes/app_pages.dart';
+
+Future loginVerify(bool check, GetNavConfig route,
+ Future Function(GetNavConfig) redirector) async {
+ final newRoute = route.location == Routes.LOGIN
+ ? Routes.LOGIN
+ : Routes.LOGIN_THEN(route.location);
+ if (check) {
+ return GetNavConfig.fromRoute(newRoute);
+ }
+
+ // Below could be used if the login was happening without verification.
+ // This will never get reached if server is sending error in login due to non verification
+ // With customClaims status == "creating", it will reach here for SignUp case only
+ if (!AuthService.to.isEmailVerified && !AuthService.to.registered.value) {
+ return GetNavConfig.fromRoute(route.location == Routes.REGISTER
+ ? Routes.REGISTER
+ : Routes.REGISTER_THEN(route.location));
+ }
+
+ return await redirector(route);
+}
+
+// class EnsureAuthMiddleware extends GetMiddleware {
+// @override
+// Future redirectDelegate(GetNavConfig route) async {
+// // you can do whatever you want here
+// // but it's preferable to make this method fast
+
+// return await loginVerify(
+// !AuthService.to.isLoggedInValue, route, super.redirectDelegate);
+// }
+// }
+
+class EnsureNotAuthedOrGuestMiddleware extends GetMiddleware {
+ //AccessLevel.notAuthed
+ @override
+ Future redirectDelegate(GetNavConfig route) async {
+ if (AuthService.to.isLoggedInValue && !AuthService.to.isAnon) {
+ //NEVER navigate to auth screen, when user is already authed
+ return GetNavConfig.fromRoute(
+ AuthService.to.registered.value ? Routes.HOME : Routes.REGISTER);
+ }
+ return await super.redirectDelegate(route);
+ }
+}
+
+class EnsureAuthedAndNotGuestMiddleware extends GetMiddleware {
+ //AccessLevel.authenticated
+ @override
+ Future redirectDelegate(GetNavConfig route) async {
+ return await loginVerify(
+ !AuthService.to.isLoggedInValue || AuthService.to.isAnon,
+ route,
+ super.redirectDelegate);
+ }
+}
+
+class EnsureRoleMiddleware extends GetMiddleware {
+ //AccessLevel.roleBased
+ Role role;
+ EnsureRoleMiddleware(this.role);
+
+ @override
+ Future redirectDelegate(GetNavConfig route) async {
+ if (!AuthService.to.isLoggedInValue || !AuthService.to.hasRole(role)) {
+ final newRoute = Routes.LOGIN_THEN(route.location);
+ return GetNavConfig.fromRoute(newRoute);
+ }
+ return await super.redirectDelegate(route);
+ }
+}
+
+class EnsureAuthOrGuestMiddleware extends GetMiddleware {
+ //AccessLevel.guest
+ @override
+ Future redirectDelegate(GetNavConfig route) async {
+ // you can do whatever you want here
+ // but it's preferable to make this method fast
+ // In this case this is taking human input and is not fast
+
+ if (!AuthService.to.isLoggedInValue) {
+ bool? value = await AuthService.to.guest();
+ if (value != true) {
+ return GetNavConfig.fromRoute(Routes.LOGIN);
+ }
+ }
+ return await super.redirectDelegate(route);
+ }
+}
diff --git a/lib/app/modules/cart/bindings/cart_binding.dart b/lib/app/modules/cart/bindings/cart_binding.dart
index 009c52ae..726c2b7c 100644
--- a/lib/app/modules/cart/bindings/cart_binding.dart
+++ b/lib/app/modules/cart/bindings/cart_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/cart_controller.dart';
-
-class CartBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => CartController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/cart_controller.dart';
+
+class CartBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => CartController(),
+ );
+ }
+}
diff --git a/lib/app/modules/cart/controllers/cart_controller.dart b/lib/app/modules/cart/controllers/cart_controller.dart
index c938ec4c..0d0c2b04 100644
--- a/lib/app/modules/cart/controllers/cart_controller.dart
+++ b/lib/app/modules/cart/controllers/cart_controller.dart
@@ -4,6 +4,10 @@ class CartController extends GetxController {
//TODO: Implement CartController
final count = 0.obs;
+<<<<<<< HEAD
+
+
+=======
@override
void onInit() {
super.onInit();
@@ -18,6 +22,7 @@ class CartController extends GetxController {
void onClose() {
super.onClose();
}
+>>>>>>> origin/main
void increment() => count.value++;
}
diff --git a/lib/app/modules/cart/views/cart_view.dart b/lib/app/modules/cart/views/cart_view.dart
index 3e048c79..e5a2f1ee 100644
--- a/lib/app/modules/cart/views/cart_view.dart
+++ b/lib/app/modules/cart/views/cart_view.dart
@@ -1,27 +1,27 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-import 'package:get_flutter_fire/app/routes/app_pages.dart';
-import '../../../widgets/screen_widget.dart';
-import '../../../../services/auth_service.dart';
-import '../controllers/cart_controller.dart';
-
-class CartView extends GetView {
- const CartView({super.key});
- @override
- Widget build(BuildContext context) {
- return ScreenWidget(
- appBar: AppBar(
- title: Text('${AuthService.to.userName} Cart'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'CartView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- screen: screen!,
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+import 'package:get_flutter_fire/app/routes/app_pages.dart';
+import '../../../widgets/screen_widget.dart';
+import '../../../../services/auth_service.dart';
+import '../controllers/cart_controller.dart';
+
+class CartView extends GetView {
+ const CartView({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return ScreenWidget(
+ appBar: AppBar(
+ title: Text('${AuthService.to.userName} Cart'),
+ centerTitle: true,
+ ),
+ body: const Center(
+ child: Text(
+ 'CartView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ screen: screen!,
+ );
+ }
+}
diff --git a/lib/app/modules/categories/bindings/categories_binding.dart b/lib/app/modules/categories/bindings/categories_binding.dart
index 06e278c8..8c460c0c 100644
--- a/lib/app/modules/categories/bindings/categories_binding.dart
+++ b/lib/app/modules/categories/bindings/categories_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/categories_controller.dart';
-
-class CategoriesBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => CategoriesController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/categories_controller.dart';
+
+class CategoriesBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => CategoriesController(),
+ );
+ }
+}
diff --git a/lib/app/modules/categories/controllers/categories_controller.dart b/lib/app/modules/categories/controllers/categories_controller.dart
index 6612e511..0b29076b 100644
--- a/lib/app/modules/categories/controllers/categories_controller.dart
+++ b/lib/app/modules/categories/controllers/categories_controller.dart
@@ -4,6 +4,10 @@ class CategoriesController extends GetxController {
//TODO: Implement CategoriesController
final count = 0.obs;
+<<<<<<< HEAD
+
+
+=======
@override
void onInit() {
super.onInit();
@@ -18,6 +22,7 @@ class CategoriesController extends GetxController {
void onClose() {
super.onClose();
}
+>>>>>>> origin/main
void increment() => count.value++;
}
diff --git a/lib/app/modules/categories/views/categories_view.dart b/lib/app/modules/categories/views/categories_view.dart
index 97bfef38..0929b08d 100644
--- a/lib/app/modules/categories/views/categories_view.dart
+++ b/lib/app/modules/categories/views/categories_view.dart
@@ -1,24 +1,24 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/categories_controller.dart';
-
-class CategoriesView extends GetView {
- const CategoriesView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('CategoriesView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'CategoriesView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/categories_controller.dart';
+
+class CategoriesView extends GetView {
+ const CategoriesView({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('CategoriesView'),
+ centerTitle: true,
+ ),
+ body: const Center(
+ child: Text(
+ 'CategoriesView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/checkout/bindings/checkout_binding.dart b/lib/app/modules/checkout/bindings/checkout_binding.dart
index 42202b56..8cd82d35 100644
--- a/lib/app/modules/checkout/bindings/checkout_binding.dart
+++ b/lib/app/modules/checkout/bindings/checkout_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/checkout_controller.dart';
-
-class CheckoutBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => CheckoutController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/checkout_controller.dart';
+
+class CheckoutBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => CheckoutController(),
+ );
+ }
+}
diff --git a/lib/app/modules/checkout/controllers/checkout_controller.dart b/lib/app/modules/checkout/controllers/checkout_controller.dart
index aa1265f6..8bd33ab8 100644
--- a/lib/app/modules/checkout/controllers/checkout_controller.dart
+++ b/lib/app/modules/checkout/controllers/checkout_controller.dart
@@ -4,6 +4,10 @@ class CheckoutController extends GetxController {
//TODO: Implement CheckoutController
final count = 0.obs;
+<<<<<<< HEAD
+
+
+=======
@override
void onInit() {
super.onInit();
@@ -18,6 +22,7 @@ class CheckoutController extends GetxController {
void onClose() {
super.onClose();
}
+>>>>>>> origin/main
void increment() => count.value++;
}
diff --git a/lib/app/modules/checkout/views/checkout_view.dart b/lib/app/modules/checkout/views/checkout_view.dart
index b8b17072..9574edb6 100644
--- a/lib/app/modules/checkout/views/checkout_view.dart
+++ b/lib/app/modules/checkout/views/checkout_view.dart
@@ -1,24 +1,24 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/checkout_controller.dart';
-
-class CheckoutView extends GetView {
- const CheckoutView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('CheckoutView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'CheckoutView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/checkout_controller.dart';
+
+class CheckoutView extends GetView {
+ const CheckoutView({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('CheckoutView'),
+ centerTitle: true,
+ ),
+ body: const Center(
+ child: Text(
+ 'CheckoutView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/dashboard/bindings/dashboard_binding.dart b/lib/app/modules/dashboard/bindings/dashboard_binding.dart
index da48f13c..1aeffcd6 100644
--- a/lib/app/modules/dashboard/bindings/dashboard_binding.dart
+++ b/lib/app/modules/dashboard/bindings/dashboard_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/dashboard_controller.dart';
-
-class DashboardBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => DashboardController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/dashboard_controller.dart';
+
+class DashboardBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => DashboardController(),
+ );
+ }
+}
diff --git a/lib/app/modules/dashboard/controllers/dashboard_controller.dart b/lib/app/modules/dashboard/controllers/dashboard_controller.dart
index 24d91a16..95555821 100644
--- a/lib/app/modules/dashboard/controllers/dashboard_controller.dart
+++ b/lib/app/modules/dashboard/controllers/dashboard_controller.dart
@@ -1,17 +1,17 @@
-import 'dart:async';
-
-import 'package:get/get.dart';
-
-class DashboardController extends GetxController {
- final now = DateTime.now().obs;
- @override
- void onReady() {
- super.onReady();
- Timer.periodic(
- const Duration(seconds: 1),
- (timer) {
- now.value = DateTime.now();
- },
- );
- }
-}
+import 'dart:async';
+
+import 'package:get/get.dart';
+
+class DashboardController extends GetxController {
+ final now = DateTime.now().obs;
+ @override
+ void onReady() {
+ super.onReady();
+ Timer.periodic(
+ const Duration(seconds: 1),
+ (timer) {
+ now.value = DateTime.now();
+ },
+ );
+ }
+}
diff --git a/lib/app/modules/dashboard/views/dashboard_view.dart b/lib/app/modules/dashboard/views/dashboard_view.dart
index f475030f..5c11b0b1 100644
--- a/lib/app/modules/dashboard/views/dashboard_view.dart
+++ b/lib/app/modules/dashboard/views/dashboard_view.dart
@@ -1,28 +1,28 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../controllers/dashboard_controller.dart';
-
-class DashboardView extends GetView {
- const DashboardView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Center(
- child: Obx(
- () => Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const Text(
- 'DashboardView is working',
- style: TextStyle(fontSize: 20),
- ),
- Text('Time: ${controller.now.value.toString()}'),
- ],
- ),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../controllers/dashboard_controller.dart';
+
+class DashboardView extends GetView {
+ const DashboardView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: Obx(
+ () => Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Text(
+ 'DashboardView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ Text('Time: ${controller.now.value.toString()}'),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/home/bindings/home_binding.dart b/lib/app/modules/home/bindings/home_binding.dart
index d08a80d4..e1df08bd 100644
--- a/lib/app/modules/home/bindings/home_binding.dart
+++ b/lib/app/modules/home/bindings/home_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/home_controller.dart';
-
-class HomeBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => HomeController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/home_controller.dart';
+
+class HomeBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => HomeController(),
+ );
+ }
+}
diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart
index f058de2a..64210698 100644
--- a/lib/app/modules/home/controllers/home_controller.dart
+++ b/lib/app/modules/home/controllers/home_controller.dart
@@ -1,14 +1,14 @@
-import 'package:get/get.dart';
-
-import '../../../../models/role.dart';
-import '../../../../services/auth_service.dart';
-
-class HomeController extends GetxController {
- final Rx chosenRole = Rx(AuthService.to.maxRole);
-
- // Role get role => AuthService.to.maxRole;
-
- get isBuyer => chosenRole.value == Role.buyer;
-
- get isAdmin => chosenRole.value == Role.admin;
-}
+import 'package:get/get.dart';
+
+import '../../../../models/role.dart';
+import '../../../../services/auth_service.dart';
+
+class HomeController extends GetxController {
+ final Rx chosenRole = Rx(AuthService.to.maxRole);
+
+ // Role get role => AuthService.to.maxRole;
+
+ get isBuyer => chosenRole.value == Role.buyer;
+
+ get isAdmin => chosenRole.value == Role.admin;
+}
diff --git a/lib/app/modules/home/views/home_view.dart b/lib/app/modules/home/views/home_view.dart
index 0cfc040d..44614973 100644
--- a/lib/app/modules/home/views/home_view.dart
+++ b/lib/app/modules/home/views/home_view.dart
@@ -1,34 +1,34 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import '../../../routes/app_pages.dart';
-import '../../../widgets/screen_widget.dart';
-import '../controllers/home_controller.dart';
-
-class HomeView extends GetView {
- const HomeView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return GetRouterOutlet.builder(
- builder: (context, delegate, currentRoute) {
- var arg = Get.rootDelegate.arguments();
- if (arg != null) {
- controller.chosenRole.value = arg["role"];
- }
- var route = controller.chosenRole.value.tabs[0].route;
- //This router outlet handles the appbar and the bottom navigation bar
- return ScreenWidget(
- screen: screen!,
- body: GetRouterOutlet(
- initialRoute: route,
- // anchorRoute: Routes.HOME,
- key: Get.nestedKey(route),
- ),
- role: controller.chosenRole.value,
- delegate: delegate,
- currentRoute: currentRoute,
- );
- },
- );
- }
-}
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import '../../../routes/app_pages.dart';
+import '../../../widgets/screen_widget.dart';
+import '../controllers/home_controller.dart';
+
+class HomeView extends GetView {
+ const HomeView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return GetRouterOutlet.builder(
+ builder: (context, delegate, currentRoute) {
+ var arg = Get.rootDelegate.arguments();
+ if (arg != null) {
+ controller.chosenRole.value = arg["role"];
+ }
+ var route = controller.chosenRole.value.tabs[0].route;
+ //This router outlet handles the appbar and the bottom navigation bar
+ return ScreenWidget(
+ screen: screen!,
+ body: GetRouterOutlet(
+ initialRoute: route,
+ // anchorRoute: Routes.HOME,
+ key: Get.nestedKey(route),
+ ),
+ role: controller.chosenRole.value,
+ delegate: delegate,
+ currentRoute: currentRoute,
+ );
+ },
+ );
+ }
+}
diff --git a/lib/app/modules/login/bindings/login_binding.dart b/lib/app/modules/login/bindings/login_binding.dart
index ac119f4a..fc19d196 100644
--- a/lib/app/modules/login/bindings/login_binding.dart
+++ b/lib/app/modules/login/bindings/login_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/login_controller.dart';
-
-class LoginBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => LoginController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/login_controller.dart';
+
+class LoginBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => LoginController(),
+ );
+ }
+}
diff --git a/lib/app/modules/login/controllers/login_controller.dart b/lib/app/modules/login/controllers/login_controller.dart
index 5178fec9..cd1e0b9f 100644
--- a/lib/app/modules/login/controllers/login_controller.dart
+++ b/lib/app/modules/login/controllers/login_controller.dart
@@ -1,20 +1,20 @@
-import 'package:get/get.dart';
-
-import '../../../../services/auth_service.dart';
-
-class LoginController extends GetxController {
- static AuthService get to => Get.find();
-
- final Rx showReverificationButton = Rx(false);
-
- bool get isRobot => AuthService.to.robot.value == true;
-
- set robot(bool v) => AuthService.to.robot.value = v;
-
- bool get isLoggedIn => AuthService.to.isLoggedInValue;
-
- bool get isAnon => AuthService.to.isAnon;
-
- bool get isRegistered =>
- AuthService.to.registered.value || AuthService.to.isEmailVerified;
-}
+import 'package:get/get.dart';
+
+import '../../../../services/auth_service.dart';
+
+class LoginController extends GetxController {
+ static AuthService get to => Get.find();
+
+ final Rx showReverificationButton = Rx(false);
+
+ bool get isRobot => AuthService.to.robot.value == true;
+
+ set robot(bool v) => AuthService.to.robot.value = v;
+
+ bool get isLoggedIn => AuthService.to.isLoggedInValue;
+
+ bool get isAnon => AuthService.to.isAnon;
+
+ bool get isRegistered =>
+ AuthService.to.registered.value || AuthService.to.isEmailVerified;
+}
diff --git a/lib/app/modules/login/views/login_view.dart b/lib/app/modules/login/views/login_view.dart
index 00c3af3f..4c44a4db 100644
--- a/lib/app/modules/login/views/login_view.dart
+++ b/lib/app/modules/login/views/login_view.dart
@@ -5,9 +5,15 @@ import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
+<<<<<<< HEAD
+
+import '../../../../models/screens.dart';
+// import '../../../controllers/recaptcha_controller.dart';
+=======
import '../../../../firebase_options.dart';
import '../../../../models/screens.dart';
+>>>>>>> origin/main
import '../../../widgets/login_widgets.dart';
import '../controllers/login_controller.dart';
@@ -125,6 +131,14 @@ class LoginView extends GetView {
}
}
+<<<<<<< HEAD
+class DefaultFirebaseOptions {
+ static var webClientId;
+}
+
+
+=======
+>>>>>>> origin/main
class MyEmailAuthProvider extends EmailAuthProvider {
@override
void onCredentialReceived(
@@ -160,3 +174,43 @@ class EmailLinkButton extends StatelessWidget {
child: const Text('Resend Verification Mail')))));
}
}
+<<<<<<< HEAD
+// import 'package:flutter/material.dart';
+// import 'package:get/get.dart';
+// // import 'package:app/controllers/recaptcha_controller.dart';
+//
+// import '../../../../controllers/recaptcha_controller.dart';
+//
+// class LoginScreen extends StatelessWidget {
+// final ReCaptchaController reCaptchaController = Get.put(ReCaptchaController());
+//
+// @override
+// Widget build(BuildContext context) {
+// return Scaffold(
+// appBar: AppBar(title: Text('Login')),
+// body: Padding(
+// padding: const EdgeInsets.all(16.0),
+// child: Column(
+// children: [
+// TextField(
+// decoration: InputDecoration(labelText: 'Email'),
+// ),
+// TextField(
+// decoration: InputDecoration(labelText: 'Password'),
+// obscureText: true,
+// ),
+// SizedBox(height: 20),
+// Obx(() => reCaptchaController.isVerified.value
+// ? ElevatedButton(onPressed: () {}, child: Text('Login'))
+// : ElevatedButton(
+// onPressed: reCaptchaController.verifyRecaptcha,
+// child: Text('Verify ReCaptcha'),
+// )),
+// ],
+// ),
+// ),
+// );
+// }
+// }
+=======
+>>>>>>> origin/main
diff --git a/lib/app/modules/my_products/bindings/my_products_binding.dart b/lib/app/modules/my_products/bindings/my_products_binding.dart
index a537f047..c45f0a98 100644
--- a/lib/app/modules/my_products/bindings/my_products_binding.dart
+++ b/lib/app/modules/my_products/bindings/my_products_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/my_products_controller.dart';
-
-class MyProductsBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => MyProductsController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/my_products_controller.dart';
+
+class MyProductsBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => MyProductsController(),
+ );
+ }
+}
diff --git a/lib/app/modules/my_products/controllers/my_products_controller.dart b/lib/app/modules/my_products/controllers/my_products_controller.dart
index 31696ea2..8d90d6b8 100644
--- a/lib/app/modules/my_products/controllers/my_products_controller.dart
+++ b/lib/app/modules/my_products/controllers/my_products_controller.dart
@@ -4,6 +4,10 @@ class MyProductsController extends GetxController {
//TODO: Implement MyProductsController
final count = 0.obs;
+<<<<<<< HEAD
+
+
+=======
@override
void onInit() {
super.onInit();
@@ -18,6 +22,7 @@ class MyProductsController extends GetxController {
void onClose() {
super.onClose();
}
+>>>>>>> origin/main
void increment() => count.value++;
}
diff --git a/lib/app/modules/my_products/views/my_products_view.dart b/lib/app/modules/my_products/views/my_products_view.dart
index 43793ebb..722bc99d 100644
--- a/lib/app/modules/my_products/views/my_products_view.dart
+++ b/lib/app/modules/my_products/views/my_products_view.dart
@@ -1,24 +1,24 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/my_products_controller.dart';
-
-class MyProductsView extends GetView {
- const MyProductsView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('MyProductsView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'MyProductsView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/my_products_controller.dart';
+
+class MyProductsView extends GetView {
+ const MyProductsView({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('MyProductsView'),
+ centerTitle: true,
+ ),
+ body: const Center(
+ child: Text(
+ 'MyProductsView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/product_details/bindings/product_details_binding.dart b/lib/app/modules/product_details/bindings/product_details_binding.dart
index 624d55ac..a587dbaa 100644
--- a/lib/app/modules/product_details/bindings/product_details_binding.dart
+++ b/lib/app/modules/product_details/bindings/product_details_binding.dart
@@ -1,14 +1,14 @@
-import 'package:get/get.dart';
-
-import '../controllers/product_details_controller.dart';
-
-class ProductDetailsBinding extends Bindings {
- @override
- void dependencies() {
- Get.create(
- () => ProductDetailsController(
- Get.parameters['productId'] ?? '',
- ),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/product_details_controller.dart';
+
+class ProductDetailsBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.create(
+ () => ProductDetailsController(
+ Get.parameters['productId'] ?? '',
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/product_details/controllers/product_details_controller.dart b/lib/app/modules/product_details/controllers/product_details_controller.dart
index d894e10c..cb433450 100644
--- a/lib/app/modules/product_details/controllers/product_details_controller.dart
+++ b/lib/app/modules/product_details/controllers/product_details_controller.dart
@@ -1,18 +1,18 @@
-import 'package:get/get.dart';
-
-class ProductDetailsController extends GetxController {
- final String productId;
-
- ProductDetailsController(this.productId);
- @override
- void onInit() {
- super.onInit();
- Get.log('ProductDetailsController created with id: $productId');
- }
-
- @override
- void onClose() {
- Get.log('ProductDetailsController close with id: $productId');
- super.onClose();
- }
-}
+import 'package:get/get.dart';
+
+class ProductDetailsController extends GetxController {
+ final String productId;
+
+ ProductDetailsController(this.productId);
+ @override
+ void onInit() {
+ super.onInit();
+ Get.log('ProductDetailsController created with id: $productId');
+ }
+
+ @override
+ void onClose() {
+ Get.log('ProductDetailsController close with id: $productId');
+ super.onClose();
+ }
+}
diff --git a/lib/app/modules/product_details/views/product_details_view.dart b/lib/app/modules/product_details/views/product_details_view.dart
index c9290724..2ae3bf4f 100644
--- a/lib/app/modules/product_details/views/product_details_view.dart
+++ b/lib/app/modules/product_details/views/product_details_view.dart
@@ -1,27 +1,27 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/product_details_controller.dart';
-
-class ProductDetailsView extends GetWidget {
- const ProductDetailsView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: Center(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const Text(
- 'ProductDetailsView is working',
- style: TextStyle(fontSize: 20),
- ),
- Text('ProductId: ${controller.productId}')
- ],
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/product_details_controller.dart';
+
+class ProductDetailsView extends GetWidget {
+ const ProductDetailsView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Text(
+ 'ProductDetailsView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ Text('ProductId: ${controller.productId}')
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/products/bindings/products_binding.dart b/lib/app/modules/products/bindings/products_binding.dart
index e7c762db..71b3e33c 100644
--- a/lib/app/modules/products/bindings/products_binding.dart
+++ b/lib/app/modules/products/bindings/products_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/products_controller.dart';
-
-class ProductsBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => ProductsController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/products_controller.dart';
+
+class ProductsBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => ProductsController(),
+ );
+ }
+}
diff --git a/lib/app/modules/products/controllers/products_controller.dart b/lib/app/modules/products/controllers/products_controller.dart
index 118c7dc8..800bf402 100644
--- a/lib/app/modules/products/controllers/products_controller.dart
+++ b/lib/app/modules/products/controllers/products_controller.dart
@@ -1,28 +1,28 @@
-import 'package:get/get.dart';
-
-import '../../../../models/product.dart';
-
-class ProductsController extends GetxController {
- final products = [].obs;
-
- void loadDemoProductsFromSomeWhere() {
- products.add(
- Product(
- name: 'Product added on: ${DateTime.now().toString()}',
- id: DateTime.now().millisecondsSinceEpoch.toString(),
- ),
- );
- }
-
- @override
- void onReady() {
- super.onReady();
- loadDemoProductsFromSomeWhere();
- }
-
- @override
- void onClose() {
- Get.printInfo(info: 'Products: onClose');
- super.onClose();
- }
-}
+import 'package:get/get.dart';
+
+import '../../../../models/product.dart';
+
+class ProductsController extends GetxController {
+ final products = [].obs;
+
+ void loadDemoProductsFromSomeWhere() {
+ products.add(
+ Product(
+ name: 'Product added on: ${DateTime.now().toString()}',
+ id: DateTime.now().millisecondsSinceEpoch.toString(),
+ ),
+ );
+ }
+
+ @override
+ void onReady() {
+ super.onReady();
+ loadDemoProductsFromSomeWhere();
+ }
+
+ @override
+ void onClose() {
+ Get.printInfo(info: 'Products: onClose');
+ super.onClose();
+ }
+}
diff --git a/lib/app/modules/products/views/products_view.dart b/lib/app/modules/products/views/products_view.dart
index 5b190a6a..c63a6607 100644
--- a/lib/app/modules/products/views/products_view.dart
+++ b/lib/app/modules/products/views/products_view.dart
@@ -1,58 +1,58 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../../../../models/role.dart';
-import '../../../routes/app_pages.dart';
-import '../controllers/products_controller.dart';
-
-class ProductsView extends GetView {
- const ProductsView({super.key});
-
- @override
- Widget build(BuildContext context) {
- var arg = Get.rootDelegate.arguments();
- return Scaffold(
- floatingActionButton:
- (arg != null && Get.rootDelegate.arguments()["role"] == Role.seller)
- ? FloatingActionButton.extended(
- onPressed: controller.loadDemoProductsFromSomeWhere,
- label: const Text('Add'),
- )
- : null,
- body: Column(
- children: [
- const Hero(
- tag: 'heroLogo',
- child: FlutterLogo(),
- ),
- Expanded(
- child: Obx(
- () => RefreshIndicator(
- onRefresh: () async {
- controller.products.clear();
- controller.loadDemoProductsFromSomeWhere();
- },
- child: ListView.builder(
- itemCount: controller.products.length,
- itemBuilder: (context, index) {
- final item = controller.products[index];
- return ListTile(
- onTap: () {
- Get.rootDelegate.toNamed(Routes.PRODUCT_DETAILS(
- item.id)); //we could use Get Parameters
- },
- title: Text(item.name),
- subtitle: Text(item.id),
- );
- },
- ),
- ),
- ),
- ),
- ],
- ),
- );
- }
-}
+// ignore_for_file: inference_failure_on_function_invocation
+
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../../../../models/role.dart';
+import '../../../routes/app_pages.dart';
+import '../controllers/products_controller.dart';
+
+class ProductsView extends GetView {
+ const ProductsView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ var arg = Get.rootDelegate.arguments();
+ return Scaffold(
+ floatingActionButton:
+ (arg != null && Get.rootDelegate.arguments()["role"] == Role.seller)
+ ? FloatingActionButton.extended(
+ onPressed: controller.loadDemoProductsFromSomeWhere,
+ label: const Text('Add'),
+ )
+ : null,
+ body: Column(
+ children: [
+ const Hero(
+ tag: 'heroLogo',
+ child: FlutterLogo(),
+ ),
+ Expanded(
+ child: Obx(
+ () => RefreshIndicator(
+ onRefresh: () async {
+ controller.products.clear();
+ controller.loadDemoProductsFromSomeWhere();
+ },
+ child: ListView.builder(
+ itemCount: controller.products.length,
+ itemBuilder: (context, index) {
+ final item = controller.products[index];
+ return ListTile(
+ onTap: () {
+ Get.rootDelegate.toNamed(Routes.PRODUCT_DETAILS(
+ item.id)); //we could use Get Parameters
+ },
+ title: Text(item.name),
+ subtitle: Text(item.id),
+ );
+ },
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/profile/bindings/profile_binding.dart b/lib/app/modules/profile/bindings/profile_binding.dart
index 5eb3b2bd..8d4a1875 100644
--- a/lib/app/modules/profile/bindings/profile_binding.dart
+++ b/lib/app/modules/profile/bindings/profile_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/profile_controller.dart';
-
-class ProfileBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => ProfileController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/profile_controller.dart';
+
+class ProfileBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => ProfileController(),
+ );
+ }
+}
diff --git a/lib/app/modules/profile/controllers/profile_controller.dart b/lib/app/modules/profile/controllers/profile_controller.dart
index 0c1e059e..4e58fda3 100644
--- a/lib/app/modules/profile/controllers/profile_controller.dart
+++ b/lib/app/modules/profile/controllers/profile_controller.dart
@@ -1,62 +1,62 @@
-import 'dart:io';
-
-import 'package:firebase_auth/firebase_auth.dart';
-import 'package:firebase_storage/firebase_storage.dart';
-import 'package:get/get.dart';
-import 'package:get_storage/get_storage.dart';
-
-import 'package:path/path.dart';
-import '../../../../services/auth_service.dart';
-
-class ProfileController extends GetxController {
- FirebaseStorage storage = FirebaseStorage.instance;
- User? currentUser = AuthService.to.user;
- final Rxn _photoURL = Rxn();
-
- File? _photo;
-
- String? get photoURL => _photoURL.value;
-
- @override
- onInit() {
- super.onInit();
- _photoURL.value = currentUser!.photoURL;
- _photoURL.bindStream(currentUser!.photoURL.obs.stream);
- }
-
- Future uploadFile(String path) async {
- try {
- var byt = GetStorage().read(path);
- if (byt != null) {
- final fileName = path;
- final destination = 'profilePics/${currentUser!.uid}';
-
- final ref = storage.ref(destination).child(fileName);
- await ref.putData(byt);
- return "$destination/$fileName";
- } else {
- _photo = File(path);
- if (_photo == null) return null;
- final fileName = basename(_photo!.path);
- final destination = 'profilePics/${currentUser!.uid}';
-
- final ref = storage.ref(destination).child(fileName);
- await ref.putFile(_photo!);
- return "$destination/$fileName";
- }
- } catch (e) {
- Get.snackbar('Error', 'Image Not Uploaded as ${e.toString()}');
- }
- return null;
- }
-
- void logout() {
- AuthService.to.logout();
- }
-
- Future updatePhotoURL(String dest) async {
- _photoURL.value = await storage.ref().child(dest).getDownloadURL();
- await currentUser?.updatePhotoURL(_photoURL.value);
- Get.snackbar('Success', 'Picture stored and linked');
- }
-}
+import 'dart:io';
+
+import 'package:firebase_auth/firebase_auth.dart';
+import 'package:firebase_storage/firebase_storage.dart';
+import 'package:get/get.dart';
+import 'package:get_storage/get_storage.dart';
+
+import 'package:path/path.dart';
+import '../../../../services/auth_service.dart';
+
+class ProfileController extends GetxController {
+ FirebaseStorage storage = FirebaseStorage.instance;
+ User? currentUser = AuthService.to.user;
+ final Rxn _photoURL = Rxn();
+
+ File? _photo;
+
+ String? get photoURL => _photoURL.value;
+
+ @override
+ onInit() {
+ super.onInit();
+ _photoURL.value = currentUser!.photoURL;
+ _photoURL.bindStream(currentUser!.photoURL.obs.stream);
+ }
+
+ Future uploadFile(String path) async {
+ try {
+ var byt = GetStorage().read(path);
+ if (byt != null) {
+ final fileName = path;
+ final destination = 'profilePics/${currentUser!.uid}';
+
+ final ref = storage.ref(destination).child(fileName);
+ await ref.putData(byt);
+ return "$destination/$fileName";
+ } else {
+ _photo = File(path);
+ if (_photo == null) return null;
+ final fileName = basename(_photo!.path);
+ final destination = 'profilePics/${currentUser!.uid}';
+
+ final ref = storage.ref(destination).child(fileName);
+ await ref.putFile(_photo!);
+ return "$destination/$fileName";
+ }
+ } catch (e) {
+ Get.snackbar('Error', 'Image Not Uploaded as ${e.toString()}');
+ }
+ return null;
+ }
+
+ void logout() {
+ AuthService.to.logout();
+ }
+
+ Future updatePhotoURL(String dest) async {
+ _photoURL.value = await storage.ref().child(dest).getDownloadURL();
+ await currentUser?.updatePhotoURL(_photoURL.value);
+ Get.snackbar('Success', 'Picture stored and linked');
+ }
+}
diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart
index c26d11c1..ced9be33 100644
--- a/lib/app/modules/profile/views/profile_view.dart
+++ b/lib/app/modules/profile/views/profile_view.dart
@@ -12,6 +12,19 @@ import '../controllers/profile_controller.dart';
class ProfileView extends GetView {
const ProfileView({super.key});
+<<<<<<< HEAD
+
+ ShapeBorder get shape => const CircleBorder();
+
+ double get size => 120;
+
+ Color get placeholderColor => Colors.grey;
+
+ Widget _imageFrameBuilder(BuildContext context,
+ Widget? child,
+ int? frame,
+ bool? _,) {
+=======
ShapeBorder get shape => const CircleBorder();
double get size => 120;
Color get placeholderColor => Colors.grey;
@@ -22,6 +35,7 @@ class ProfileView extends GetView {
int? frame,
bool? _,
) {
+>>>>>>> origin/main
if (frame == null) {
return Container(color: placeholderColor);
}
@@ -37,6 +51,80 @@ class ProfileView extends GetView {
Widget profileScreen() {
return AuthService.to.isLoggedInValue
? ProfileScreen(
+<<<<<<< HEAD
+ // We are using the Flutter Fire Profile Screen now but will change in subsequent steps.
+ // The issues are highlighted in comments here
+
+ // appBar: AppBar(
+ // title: const Text('User Profile'),
+ // ),
+ avatar: SizedBox(
+ //null will give the profile image component but it does not refresh the pic when changed
+ height: size,
+ width: size,
+ child: ClipPath(
+ clipper: ShapeBorderClipper(shape: shape),
+ clipBehavior: Clip.hardEdge,
+ child: controller.photoURL != null
+ ? Image.network(
+ controller.photoURL!,
+ width: size,
+ height: size,
+ cacheWidth: size.toInt(),
+ cacheHeight: size.toInt(),
+ fit: BoxFit.contain,
+ frameBuilder: _imageFrameBuilder,
+ )
+ : Center(
+ child: Image.asset(
+ 'assets/images/dash.png',
+ width: size,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ),
+ ),
+ // showDeleteConfirmationDialog: true, //this does not work properly. Possibly a bug in FlutterFire
+ actions: [
+ SignedOutAction((context) {
+ Get.back();
+ controller.logout();
+ Get.rootDelegate.toNamed(Screen.PROFILE.route);
+ // Navigator.of(context).pop();
+ }),
+ AccountDeletedAction((context, user) {
+ //If we don't include this the button is still shown but no action gets done. Ideally the button should also not be shown. Its a bug in FlutterFire
+ Get.defaultDialog(
+ //this is only called after the delete is done and not useful for confirmation of the delete action
+ title: 'Deleted Account of ${user.displayName}',
+ barrierDismissible: true,
+ navigatorKey: Get.nestedKey(Screen.HOME.route),
+ );
+ })
+ ],
+ children: [
+ //This is to show that we can add custom content here
+ const Divider(),
+ controller.currentUser?.email != null
+ ? TextButton.icon(
+ onPressed: callChangePwdDialog,
+ label: const Text('Change Password'),
+ icon: const Icon(Icons.password_rounded),
+ )
+ : const SizedBox.shrink(),
+ ImagePickerButton(callback: (String? path) async {
+ if (path != null) {
+ //Upload to Store
+ String? dest = await controller.uploadFile(path);
+ //attach it to User imageUrl
+ if (dest != null) {
+ await controller.updatePhotoURL(dest);
+ }
+ }
+ })
+ ],
+ )
+=======
// We are using the Flutter Fire Profile Screen now but will change in subsequent steps.
// The issues are highlighted in comments here
@@ -109,10 +197,31 @@ class ProfileView extends GetView {
})
],
)
+>>>>>>> origin/main
: const Scaffold();
}
void callChangePwdDialog() {
+<<<<<<< HEAD
+ // Instantiate the ChangePasswordController
+ final ChangePasswordController controller = Get.put(
+ ChangePasswordController());
+
+ // Create a dialog with the ChangePasswordScreen widget
+ Get.defaultDialog(
+ title: "Change Password",
+ content: ChangePasswordScreen(),
+ // Use ChangePasswordScreen widget
+ textConfirm: "Submit",
+ textCancel: "Cancel",
+ onConfirm: () {
+ controller.changePassword(); // Call the changePassword method
+ },
+ );
+ }
+
+}
+=======
var dlg = ChangePasswordDialog(controller.currentUser!);
Get.defaultDialog(
title: "Change Password",
@@ -122,3 +231,4 @@ class ProfileView extends GetView {
onConfirm: dlg.onSubmit);
}
}
+>>>>>>> origin/main
diff --git a/lib/app/modules/register/bindings/register_binding.dart b/lib/app/modules/register/bindings/register_binding.dart
index 1089ecbd..ffb44509 100644
--- a/lib/app/modules/register/bindings/register_binding.dart
+++ b/lib/app/modules/register/bindings/register_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/register_controller.dart';
-
-class RegisterBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => RegisterController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/register_controller.dart';
+
+class RegisterBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => RegisterController(),
+ );
+ }
+}
diff --git a/lib/app/modules/register/controllers/register_controller.dart b/lib/app/modules/register/controllers/register_controller.dart
index 96cb2cb0..a96798f0 100644
--- a/lib/app/modules/register/controllers/register_controller.dart
+++ b/lib/app/modules/register/controllers/register_controller.dart
@@ -1,23 +1,23 @@
-import 'package:get/get.dart';
-
-import '../../../../services/auth_service.dart';
-
-class RegisterController extends GetxController {
- @override
- void onInit() {
- super.onInit();
- // Send email verification and logout
- AuthService.to
- .sendVerificationMail(); //if we use the EmailVerificationScreen then no need to call this
- }
-
- // @override
- // void onReady() {
- // super.onReady();
- // }
-
- // @override
- // void onClose() {
- // super.onClose();
- // }
-}
+import 'package:get/get.dart';
+
+import '../../../../services/auth_service.dart';
+
+class RegisterController extends GetxController {
+ @override
+ void onInit() {
+ super.onInit();
+ // Send email verification and logout
+ AuthService.to
+ .sendVerificationMail(); //if we use the EmailVerificationScreen then no need to call this
+ }
+
+ // @override
+ // void onReady() {
+ // super.onReady();
+ // }
+
+ // @override
+ // void onClose() {
+ // super.onClose();
+ // }
+}
diff --git a/lib/app/modules/register/views/register_view.dart b/lib/app/modules/register/views/register_view.dart
index 01f73e88..b3a71ec9 100644
--- a/lib/app/modules/register/views/register_view.dart
+++ b/lib/app/modules/register/views/register_view.dart
@@ -1,53 +1,53 @@
-// import 'package:firebase_ui_auth/firebase_ui_auth.dart';
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../../../../services/auth_service.dart';
-// import '../../../widgets/login_widgets.dart';
-import '../controllers/register_controller.dart';
-
-//ALso add a form to take additional info such as display name of other customer details mapped with uid in Firestore
-class RegisterView extends GetView {
- const RegisterView({super.key});
-
- @override
- Widget build(BuildContext context) {
- // Add pre verification Form if any. Mostly it can be post verification and can be the Profile or Setting screens
- try {
- // using this is causing an error when we send verification mail from server side
- // if it was initiated once, even when no visible. So we need to dispose when not visible
- var w =
- // EmailVerificationScreen(
- // headerBuilder: LoginWidgets.headerBuilder,
- // sideBuilder: LoginWidgets.sideBuilder,
- // actions: [
- // EmailVerifiedAction(() {
- // AuthService.to.register();
- // }),
- // ],
- // );
- Scaffold(
- appBar: AppBar(
- title: const Text('Registeration'),
- centerTitle: true,
- ),
- body: Center(
- child: Column(children: [
- const Text(
- 'Please verify your email (check SPAM folder), and then relogin',
- style: TextStyle(fontSize: 20),
- ),
- TextButton(
- onPressed: () => AuthService.to.register(),
- child: const Text("Verification Done. Relogin"),
- )
- ])),
- );
- return w;
- } catch (e) {
- // TODO
- }
- return const Scaffold();
- }
-}
+// import 'package:firebase_ui_auth/firebase_ui_auth.dart';
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../../../../services/auth_service.dart';
+// import '../../../widgets/login_widgets.dart';
+import '../controllers/register_controller.dart';
+
+//ALso add a form to take additional info such as display name of other customer details mapped with uid in Firestore
+class RegisterView extends GetView {
+ const RegisterView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ // Add pre verification Form if any. Mostly it can be post verification and can be the Profile or Setting screens
+ try {
+ // using this is causing an error when we send verification mail from server side
+ // if it was initiated once, even when no visible. So we need to dispose when not visible
+ var w =
+ // EmailVerificationScreen(
+ // headerBuilder: LoginWidgets.headerBuilder,
+ // sideBuilder: LoginWidgets.sideBuilder,
+ // actions: [
+ // EmailVerifiedAction(() {
+ // AuthService.to.register();
+ // }),
+ // ],
+ // );
+ Scaffold(
+ appBar: AppBar(
+ title: const Text('Registeration'),
+ centerTitle: true,
+ ),
+ body: Center(
+ child: Column(children: [
+ const Text(
+ 'Please verify your email (check SPAM folder), and then relogin',
+ style: TextStyle(fontSize: 20),
+ ),
+ TextButton(
+ onPressed: () => AuthService.to.register(),
+ child: const Text("Verification Done. Relogin"),
+ )
+ ])),
+ );
+ return w;
+ } catch (e) {
+ // TODO
+ }
+ return const Scaffold();
+ }
+}
diff --git a/lib/app/modules/root/bindings/root_binding.dart b/lib/app/modules/root/bindings/root_binding.dart
index e1e94d1d..bb939fb0 100644
--- a/lib/app/modules/root/bindings/root_binding.dart
+++ b/lib/app/modules/root/bindings/root_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/root_controller.dart';
-
-class RootBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => RootController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/root_controller.dart';
+
+class RootBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => RootController(),
+ );
+ }
+}
diff --git a/lib/app/modules/root/controllers/my_drawer_controller.dart b/lib/app/modules/root/controllers/my_drawer_controller.dart
index f45ef122..cb025186 100644
--- a/lib/app/modules/root/controllers/my_drawer_controller.dart
+++ b/lib/app/modules/root/controllers/my_drawer_controller.dart
@@ -1,10 +1,10 @@
-import 'package:get/get.dart';
-
-import '../../../../models/screens.dart';
-
-class MyDrawerController extends GetxController {
- MyDrawerController(Iterable iter)
- : values = Rx>(iter);
-
- final Rx> values;
-}
+import 'package:get/get.dart';
+
+import '../../../../models/screens.dart';
+
+class MyDrawerController extends GetxController {
+ MyDrawerController(Iterable iter)
+ : values = Rx>(iter);
+
+ final Rx> values;
+}
diff --git a/lib/app/modules/root/controllers/root_controller.dart b/lib/app/modules/root/controllers/root_controller.dart
index 7f160fc6..149a5da3 100644
--- a/lib/app/modules/root/controllers/root_controller.dart
+++ b/lib/app/modules/root/controllers/root_controller.dart
@@ -1,14 +1,14 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-class RootController extends GetxController {
- GlobalKey scaffoldKey = GlobalKey();
-
- void openDrawer() {
- scaffoldKey.currentState!.openDrawer();
- }
-
- void closeDrawer() {
- scaffoldKey.currentState!.openEndDrawer();
- }
-}
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+class RootController extends GetxController {
+ GlobalKey scaffoldKey = GlobalKey();
+
+ void openDrawer() {
+ scaffoldKey.currentState!.openDrawer();
+ }
+
+ void closeDrawer() {
+ scaffoldKey.currentState!.openEndDrawer();
+ }
+}
diff --git a/lib/app/modules/root/views/drawer.dart b/lib/app/modules/root/views/drawer.dart
index 908d0223..0de8bb5b 100644
--- a/lib/app/modules/root/views/drawer.dart
+++ b/lib/app/modules/root/views/drawer.dart
@@ -1,118 +1,118 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../../../../models/role.dart';
-import '../../../../services/auth_service.dart';
-
-import '../../../../models/screens.dart';
-import '../controllers/my_drawer_controller.dart';
-
-class DrawerWidget extends StatelessWidget {
- const DrawerWidget({
- super.key,
- });
-
- @override
- Widget build(BuildContext context) {
- MyDrawerController controller = Get.put(MyDrawerController([]),
- permanent: true); //must make true else gives error
- Screen.drawer().then((v) => {controller.values.value = v});
- return Obx(() => Drawer(
- //changing the shape of the drawer
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.only(
- topRight: Radius.circular(0), bottomRight: Radius.circular(20)),
- ),
- width: 200,
- child: Column(
- children: drawerItems(context, controller.values),
- ),
- ));
- }
-
- List drawerItems(BuildContext context, Rx> values) {
- List list = [
- Container(
- height: 100,
- color: Colors.red,
- //adding content in the highlighted part of the drawer
- child: Align(
- alignment: Alignment.centerLeft,
- child: Container(
- margin: const EdgeInsets.only(left: 15),
- child: const Text('User Name', //Profile Icon also
- style: TextStyle(fontWeight: FontWeight.bold)))),
- )
- ];
-
- if (AuthService.to.maxRole.index > 1) {
- for (var i = 0; i <= AuthService.to.maxRole.index; i++) {
- Role role = Role.values[i];
- list.add(ListTile(
- title: Text(
- role.name,
- style: const TextStyle(
- color: Colors.blue,
- ),
- ),
- onTap: () {
- Get.rootDelegate
- .toNamed(Screen.HOME.route, arguments: {'role': role});
- //to close the drawer
- Navigator.of(context).pop();
- },
- ));
- }
- }
-
- for (Screen screen in values.value) {
- list.add(ListTile(
- title: Text(screen.label ?? ''),
- onTap: () {
- Get.rootDelegate.toNamed(screen.route);
- //to close the drawer
-
- Navigator.of(context).pop();
- },
- ));
- }
-
- if (AuthService.to.isLoggedInValue) {
- list.add(ListTile(
- title: const Text(
- 'Logout',
- style: TextStyle(
- color: Colors.red,
- ),
- ),
- onTap: () {
- AuthService.to.logout();
- Get.rootDelegate.toNamed(Screen.LOGIN.route);
- //to close the drawer
-
- Navigator.of(context).pop();
- },
- ));
- }
- if (!AuthService.to.isLoggedInValue) {
- list.add(ListTile(
- title: const Text(
- 'Login',
- style: TextStyle(
- color: Colors.blue,
- ),
- ),
- onTap: () {
- Get.rootDelegate.toNamed(Screen.LOGIN.route);
- //to close the drawer
-
- Navigator.of(context).pop();
- },
- ));
- }
-
- return list;
- }
-}
+// ignore_for_file: inference_failure_on_function_invocation
+
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../../../../models/role.dart';
+import '../../../../services/auth_service.dart';
+
+import '../../../../models/screens.dart';
+import '../controllers/my_drawer_controller.dart';
+
+class DrawerWidget extends StatelessWidget {
+ const DrawerWidget({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ MyDrawerController controller = Get.put(MyDrawerController([]),
+ permanent: true); //must make true else gives error
+ Screen.drawer().then((v) => {controller.values.value = v});
+ return Obx(() => Drawer(
+ //changing the shape of the drawer
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.only(
+ topRight: Radius.circular(0), bottomRight: Radius.circular(20)),
+ ),
+ width: 200,
+ child: Column(
+ children: drawerItems(context, controller.values),
+ ),
+ ));
+ }
+
+ List drawerItems(BuildContext context, Rx> values) {
+ List list = [
+ Container(
+ height: 100,
+ color: Colors.red,
+ //adding content in the highlighted part of the drawer
+ child: Align(
+ alignment: Alignment.centerLeft,
+ child: Container(
+ margin: const EdgeInsets.only(left: 15),
+ child: const Text('User Name', //Profile Icon also
+ style: TextStyle(fontWeight: FontWeight.bold)))),
+ )
+ ];
+
+ if (AuthService.to.maxRole.index > 1) {
+ for (var i = 0; i <= AuthService.to.maxRole.index; i++) {
+ Role role = Role.values[i];
+ list.add(ListTile(
+ title: Text(
+ role.name,
+ style: const TextStyle(
+ color: Colors.blue,
+ ),
+ ),
+ onTap: () {
+ Get.rootDelegate
+ .toNamed(Screen.HOME.route, arguments: {'role': role});
+ //to close the drawer
+ Navigator.of(context).pop();
+ },
+ ));
+ }
+ }
+
+ for (Screen screen in values.value) {
+ list.add(ListTile(
+ title: Text(screen.label ?? ''),
+ onTap: () {
+ Get.rootDelegate.toNamed(screen.route);
+ //to close the drawer
+
+ Navigator.of(context).pop();
+ },
+ ));
+ }
+
+ if (AuthService.to.isLoggedInValue) {
+ list.add(ListTile(
+ title: const Text(
+ 'Logout',
+ style: TextStyle(
+ color: Colors.red,
+ ),
+ ),
+ onTap: () {
+ AuthService.to.logout();
+ Get.rootDelegate.toNamed(Screen.LOGIN.route);
+ //to close the drawer
+
+ Navigator.of(context).pop();
+ },
+ ));
+ }
+ if (!AuthService.to.isLoggedInValue) {
+ list.add(ListTile(
+ title: const Text(
+ 'Login',
+ style: TextStyle(
+ color: Colors.blue,
+ ),
+ ),
+ onTap: () {
+ Get.rootDelegate.toNamed(Screen.LOGIN.route);
+ //to close the drawer
+
+ Navigator.of(context).pop();
+ },
+ ));
+ }
+
+ return list;
+ }
+}
diff --git a/lib/app/modules/root/views/root_view.dart b/lib/app/modules/root/views/root_view.dart
index 2bbf228c..adb73813 100644
--- a/lib/app/modules/root/views/root_view.dart
+++ b/lib/app/modules/root/views/root_view.dart
@@ -2,9 +2,16 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
+<<<<<<< HEAD
+// import 'package:get_flutter_fire/app/modules/root/views/root_view.dart';
+import 'package:get_flutter_fire/services/auth_service.dart';
+import '../../../../models/screens.dart';
+import '../../../routes/app_pages.dart';
+=======
import 'package:get_flutter_fire/services/auth_service.dart';
import '../../../routes/app_pages.dart';
import '../../../../models/screens.dart';
+>>>>>>> origin/main
import '../controllers/root_controller.dart';
import 'drawer.dart';
@@ -42,7 +49,11 @@ class RootView extends GetView {
// automaticallyImplyLeading: false, //removes drawer icon
),
body: GetRouterOutlet(
+<<<<<<< HEAD
+ initialRoute: AppRoutes.INITIAL,
+=======
initialRoute: AppPages.INITIAL,
+>>>>>>> origin/main
// anchorRoute: '/',
// filterPages: (afterAnchor) {
// return afterAnchor.take(1);
@@ -62,3 +73,8 @@ class RootView extends GetView {
]; //TODO add seach button
}
}
+<<<<<<< HEAD
+
+
+=======
+>>>>>>> origin/main
diff --git a/lib/app/modules/settings/bindings/settings_binding.dart b/lib/app/modules/settings/bindings/settings_binding.dart
index fb567f07..f1322688 100644
--- a/lib/app/modules/settings/bindings/settings_binding.dart
+++ b/lib/app/modules/settings/bindings/settings_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/settings_controller.dart';
-
-class SettingsBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => SettingsController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/settings_controller.dart';
+
+class SettingsBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => SettingsController(),
+ );
+ }
+}
diff --git a/lib/app/modules/settings/controllers/settings_controller.dart b/lib/app/modules/settings/controllers/settings_controller.dart
index 265e54b1..93baadb2 100644
--- a/lib/app/modules/settings/controllers/settings_controller.dart
+++ b/lib/app/modules/settings/controllers/settings_controller.dart
@@ -4,6 +4,9 @@ class SettingsController extends GetxController {
//TODO: Implement SettingsController
final count = 0.obs;
+<<<<<<< HEAD
+
+=======
@override
void onInit() {
super.onInit();
@@ -13,6 +16,7 @@ class SettingsController extends GetxController {
void onReady() {
super.onReady();
}
+>>>>>>> origin/main
@override
void onClose() {}
diff --git a/lib/app/modules/settings/views/settings_view.dart b/lib/app/modules/settings/views/settings_view.dart
index 2bb244b6..0e655767 100644
--- a/lib/app/modules/settings/views/settings_view.dart
+++ b/lib/app/modules/settings/views/settings_view.dart
@@ -1,21 +1,21 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/settings_controller.dart';
-
-class SettingsView extends GetView {
- const SettingsView({super.key});
-
- @override
- Widget build(BuildContext context) {
- return const Scaffold(
- body: Center(
- child: Text(
- 'SettingsView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/settings_controller.dart';
+
+class SettingsView extends GetView {
+ const SettingsView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return const Scaffold(
+ body: Center(
+ child: Text(
+ 'SettingsView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/task_details/bindings/task_details_binding.dart b/lib/app/modules/task_details/bindings/task_details_binding.dart
index 1e017283..7d428c27 100644
--- a/lib/app/modules/task_details/bindings/task_details_binding.dart
+++ b/lib/app/modules/task_details/bindings/task_details_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/task_details_controller.dart';
-
-class TaskDetailsBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => TaskDetailsController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/task_details_controller.dart';
+
+class TaskDetailsBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => TaskDetailsController(),
+ );
+ }
+}
diff --git a/lib/app/modules/task_details/controllers/task_details_controller.dart b/lib/app/modules/task_details/controllers/task_details_controller.dart
index e0a6a0d9..5832cc22 100644
--- a/lib/app/modules/task_details/controllers/task_details_controller.dart
+++ b/lib/app/modules/task_details/controllers/task_details_controller.dart
@@ -4,6 +4,10 @@ class TaskDetailsController extends GetxController {
//TODO: Implement TaskDetailsController
final count = 0.obs;
+<<<<<<< HEAD
+
+
+=======
@override
void onInit() {
super.onInit();
@@ -18,6 +22,7 @@ class TaskDetailsController extends GetxController {
void onClose() {
super.onClose();
}
+>>>>>>> origin/main
void increment() => count.value++;
}
diff --git a/lib/app/modules/task_details/views/task_details_view.dart b/lib/app/modules/task_details/views/task_details_view.dart
index c21dbc0e..bf97a1dc 100644
--- a/lib/app/modules/task_details/views/task_details_view.dart
+++ b/lib/app/modules/task_details/views/task_details_view.dart
@@ -1,24 +1,24 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/task_details_controller.dart';
-
-class TaskDetailsView extends GetView {
- const TaskDetailsView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('TaskDetailsView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'TaskDetailsView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/task_details_controller.dart';
+
+class TaskDetailsView extends GetView {
+ const TaskDetailsView({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('TaskDetailsView'),
+ centerTitle: true,
+ ),
+ body: const Center(
+ child: Text(
+ 'TaskDetailsView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/tasks/bindings/tasks_binding.dart b/lib/app/modules/tasks/bindings/tasks_binding.dart
index 9d836c2b..415b12f4 100644
--- a/lib/app/modules/tasks/bindings/tasks_binding.dart
+++ b/lib/app/modules/tasks/bindings/tasks_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/tasks_controller.dart';
-
-class TasksBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => TasksController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/tasks_controller.dart';
+
+class TasksBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => TasksController(),
+ );
+ }
+}
diff --git a/lib/app/modules/tasks/controllers/tasks_controller.dart b/lib/app/modules/tasks/controllers/tasks_controller.dart
index 4d4196e4..4a1bc1d0 100644
--- a/lib/app/modules/tasks/controllers/tasks_controller.dart
+++ b/lib/app/modules/tasks/controllers/tasks_controller.dart
@@ -4,6 +4,10 @@ class TasksController extends GetxController {
//TODO: Implement TasksController
final count = 0.obs;
+<<<<<<< HEAD
+
+
+=======
@override
void onInit() {
super.onInit();
@@ -18,6 +22,7 @@ class TasksController extends GetxController {
void onClose() {
super.onClose();
}
+>>>>>>> origin/main
void increment() => count.value++;
}
diff --git a/lib/app/modules/tasks/views/tasks_view.dart b/lib/app/modules/tasks/views/tasks_view.dart
index 2103103b..2a77f94b 100644
--- a/lib/app/modules/tasks/views/tasks_view.dart
+++ b/lib/app/modules/tasks/views/tasks_view.dart
@@ -1,24 +1,24 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/tasks_controller.dart';
-
-class TasksView extends GetView {
- const TasksView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('TasksView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'TasksView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/tasks_controller.dart';
+
+class TasksView extends GetView {
+ const TasksView({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('TasksView'),
+ centerTitle: true,
+ ),
+ body: const Center(
+ child: Text(
+ 'TasksView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/modules/users/bindings/users_binding.dart b/lib/app/modules/users/bindings/users_binding.dart
index 7d8efdb0..cc510b8b 100644
--- a/lib/app/modules/users/bindings/users_binding.dart
+++ b/lib/app/modules/users/bindings/users_binding.dart
@@ -1,12 +1,12 @@
-import 'package:get/get.dart';
-
-import '../controllers/users_controller.dart';
-
-class UsersBinding extends Bindings {
- @override
- void dependencies() {
- Get.lazyPut(
- () => UsersController(),
- );
- }
-}
+import 'package:get/get.dart';
+
+import '../controllers/users_controller.dart';
+
+class UsersBinding extends Bindings {
+ @override
+ void dependencies() {
+ Get.lazyPut(
+ () => UsersController(),
+ );
+ }
+}
diff --git a/lib/app/modules/users/controllers/users_controller.dart b/lib/app/modules/users/controllers/users_controller.dart
index 871467c4..f7072635 100644
--- a/lib/app/modules/users/controllers/users_controller.dart
+++ b/lib/app/modules/users/controllers/users_controller.dart
@@ -4,6 +4,10 @@ class UsersController extends GetxController {
//TODO: Implement UsersController
final count = 0.obs;
+<<<<<<< HEAD
+
+
+=======
@override
void onInit() {
super.onInit();
@@ -18,6 +22,7 @@ class UsersController extends GetxController {
void onClose() {
super.onClose();
}
+>>>>>>> origin/main
void increment() => count.value++;
}
diff --git a/lib/app/modules/users/views/users_view.dart b/lib/app/modules/users/views/users_view.dart
index 702f32da..72766fd7 100644
--- a/lib/app/modules/users/views/users_view.dart
+++ b/lib/app/modules/users/views/users_view.dart
@@ -1,24 +1,24 @@
-import 'package:flutter/material.dart';
-
-import 'package:get/get.dart';
-
-import '../controllers/users_controller.dart';
-
-class UsersView extends GetView {
- const UsersView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: const Text('UsersView'),
- centerTitle: true,
- ),
- body: const Center(
- child: Text(
- 'UsersView is working',
- style: TextStyle(fontSize: 20),
- ),
- ),
- );
- }
-}
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/users_controller.dart';
+
+class UsersView extends GetView {
+ const UsersView({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('UsersView'),
+ centerTitle: true,
+ ),
+ body: const Center(
+ child: Text(
+ 'UsersView is working',
+ style: TextStyle(fontSize: 20),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart
index 7269755d..878225c0 100644
--- a/lib/app/routes/app_pages.dart
+++ b/lib/app/routes/app_pages.dart
@@ -1,8 +1,17 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
+<<<<<<< HEAD
+import 'package:get_flutter_fire/screen/auth/login_screen.dart';
import '../../models/access_level.dart';
import '../../models/role.dart';
+import '../../screen/auth/login_screen.dart';
+
+=======
+
+import '../../models/access_level.dart';
+import '../../models/role.dart';
+>>>>>>> origin/main
import '../middleware/auth_middleware.dart';
import '../modules/cart/bindings/cart_binding.dart';
import '../modules/cart/views/cart_view.dart';
@@ -15,7 +24,10 @@ import '../modules/dashboard/views/dashboard_view.dart';
import '../modules/home/bindings/home_binding.dart';
import '../modules/home/views/home_view.dart';
import '../modules/login/bindings/login_binding.dart';
+<<<<<<< HEAD
+=======
import '../modules/login/views/login_view.dart';
+>>>>>>> origin/main
import '../modules/my_products/bindings/my_products_binding.dart';
import '../modules/my_products/views/my_products_view.dart';
import '../modules/product_details/bindings/product_details_binding.dart';
@@ -37,10 +49,18 @@ import '../modules/tasks/views/tasks_view.dart';
import '../modules/users/bindings/users_binding.dart';
import '../modules/users/views/users_view.dart';
import '../../models/screens.dart';
+<<<<<<< HEAD
+import 'package:firebase_ui_auth/firebase_ui_auth.dart' as firebase_ui_auth;
+import 'package:get_flutter_fire/app/modules/login/views/login_view.dart' as custom_login_view;
+=======
+>>>>>>> origin/main
part 'app_routes.dart';
part 'screen_extension.dart';
+<<<<<<< HEAD
+class AppRoutes {
+=======
class AppPages {
AppPages._();
@@ -48,6 +68,7 @@ class AppPages {
//TODO create this using the information from Screen and Role data
//can use https://pub.dev/packages/freezed
+>>>>>>> origin/main
static final routes = [
GetPage(
name: '/',
@@ -56,8 +77,21 @@ class AppPages {
participatesInRootNavigator: true,
preventDuplicates: true,
children: [
+<<<<<<< HEAD
+ // Use custom_login_view.LoginView if needed
+ // GetPage(
+ // name: '/login',
+ // page: () => custom_login_view.LoginScreen(), // Use custom implementation
+ // binding: LoginBinding(),
+ // ),
+ // Example of using firebase_ui_auth.LoginView if needed
+ GetPage(
+ name: '/firebase_login',
+ page: () => const firebase_ui_auth.LoginView(action: firebase_ui_auth.AuthAction.signIn, providers: [],), // Example usage
+=======
Screen.LOGIN.getPage(
page: () => const LoginView(),
+>>>>>>> origin/main
binding: LoginBinding(),
),
Screen.REGISTER.getPage(
@@ -151,4 +185,11 @@ class AppPages {
],
),
];
+<<<<<<< HEAD
+
+ static var INITIAL;
+}
+
+=======
}
+>>>>>>> origin/main
diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart
index f3129d21..ec568c8c 100644
--- a/lib/app/routes/app_routes.dart
+++ b/lib/app/routes/app_routes.dart
@@ -1,54 +1,54 @@
-// ignore_for_file: non_constant_identifier_names, constant_identifier_names
-
-part of 'app_pages.dart';
-// DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart
-
-abstract class Routes {
- static const HOME = _Paths.HOME;
- // static String PROFILE = Screen.PROFILE.fullPath;
- // static String SETTINGS = Screen.SETTINGS.fullPath;
- static String LOGIN = Screen.LOGIN.route;
- static String REGISTER = Screen.REGISTER.route;
- // static String DASHBOARD = Screen.DASHBOARD.fullPath;
- // static String PRODUCTS = Screen.PRODUCTS.fullPath;
- // static String CART = Screen.CART.fullPath;
- // static String CHECKOUT = Screen.CHECKOUT.fullPath;
- // static const CATEGORIES = _Paths.HOME + _Paths.CATEGORIES;
- // static const TASKS = _Paths.HOME + _Paths.TASKS;
- // static const USERS = _Paths.HOME + _Paths.USERS;
- // static const MY_PRODUCTS = _Paths.HOME + _Paths.MY_PRODUCTS;
-
- static String PRODUCT_DETAILS(String productId) =>
- '${Screen.PRODUCTS.route}/$productId';
- static String CART_DETAILS(String productId) =>
- '${Screen.CART.route}/$productId';
- static String TASK_DETAILS(String taskId) => '${Screen.TASKS.route}/$taskId';
- static String USER_PROFILE(String uId) => '${Screen.USERS.route}/$uId';
-
- Routes._();
- static String LOGIN_THEN(String afterSuccessfulLogin) =>
- '${Screen.LOGIN.route}?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
- static String REGISTER_THEN(String afterSuccessfulLogin) =>
- '${Screen.REGISTER.route}?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
-}
-
-// Keeping this as Get_Cli will require it. Any addition can later be added to Screen
-abstract class _Paths {
- static const String HOME = '/home';
- // static const DASHBOARD = '/dashboard';
- // static const PRODUCTS = '/products';
- // static const PROFILE = '/profile';
- // static const SETTINGS = '/settings';
- // static const PRODUCT_DETAILS = '/:productId';
- // static const CART_DETAILS = '/:productId';
- // static const LOGIN = '/login';
- // static const CART = '/cart';
- // static const CHECKOUT = '/checkout';
- // static const REGISTER = '/register';
- // static const CATEGORIES = '/categories';
- // static const TASKS = '/tasks';
- // static const TASK_DETAILS = '/:taskId';
- // static const USERS = '/users';
- // static const USER_PROFILE = '/:uId';
- // static const MY_PRODUCTS = '/my-products';
-}
+// ignore_for_file: non_constant_identifier_names, constant_identifier_names
+
+part of 'app_pages.dart';
+// DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart
+
+abstract class Routes {
+ static const HOME = _Paths.HOME;
+ // static String PROFILE = Screen.PROFILE.fullPath;
+ // static String SETTINGS = Screen.SETTINGS.fullPath;
+ static String LOGIN = Screen.LOGIN.route;
+ static String REGISTER = Screen.REGISTER.route;
+ // static String DASHBOARD = Screen.DASHBOARD.fullPath;
+ // static String PRODUCTS = Screen.PRODUCTS.fullPath;
+ // static String CART = Screen.CART.fullPath;
+ // static String CHECKOUT = Screen.CHECKOUT.fullPath;
+ // static const CATEGORIES = _Paths.HOME + _Paths.CATEGORIES;
+ // static const TASKS = _Paths.HOME + _Paths.TASKS;
+ // static const USERS = _Paths.HOME + _Paths.USERS;
+ // static const MY_PRODUCTS = _Paths.HOME + _Paths.MY_PRODUCTS;
+
+ static String PRODUCT_DETAILS(String productId) =>
+ '${Screen.PRODUCTS.route}/$productId';
+ static String CART_DETAILS(String productId) =>
+ '${Screen.CART.route}/$productId';
+ static String TASK_DETAILS(String taskId) => '${Screen.TASKS.route}/$taskId';
+ static String USER_PROFILE(String uId) => '${Screen.USERS.route}/$uId';
+
+ Routes._();
+ static String LOGIN_THEN(String afterSuccessfulLogin) =>
+ '${Screen.LOGIN.route}?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
+ static String REGISTER_THEN(String afterSuccessfulLogin) =>
+ '${Screen.REGISTER.route}?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
+}
+
+// Keeping this as Get_Cli will require it. Any addition can later be added to Screen
+abstract class _Paths {
+ static const String HOME = '/home';
+ // static const DASHBOARD = '/dashboard';
+ // static const PRODUCTS = '/products';
+ // static const PROFILE = '/profile';
+ // static const SETTINGS = '/settings';
+ // static const PRODUCT_DETAILS = '/:productId';
+ // static const CART_DETAILS = '/:productId';
+ // static const LOGIN = '/login';
+ // static const CART = '/cart';
+ // static const CHECKOUT = '/checkout';
+ // static const REGISTER = '/register';
+ // static const CATEGORIES = '/categories';
+ // static const TASKS = '/tasks';
+ // static const TASK_DETAILS = '/:taskId';
+ // static const USERS = '/users';
+ // static const USER_PROFILE = '/:uId';
+ // static const MY_PRODUCTS = '/my-products';
+}
diff --git a/lib/app/routes/screen_extension.dart b/lib/app/routes/screen_extension.dart
index aaf138b0..76e6d2f7 100644
--- a/lib/app/routes/screen_extension.dart
+++ b/lib/app/routes/screen_extension.dart
@@ -1,125 +1,125 @@
-part of 'app_pages.dart';
-
-extension GetViewExtension on GetView {
- static final _screens = Expando();
-
- Screen? get screen => _screens[this];
- set screen(Screen? x) => _screens[this] = x;
-}
-
-extension GetWidgetExtension on GetWidget {
- static final _screens = Expando();
-
- Screen? get screen => _screens[this];
- set screen(Screen? x) => _screens[this] = x;
-}
-
-extension GetPageExtension on GetPage {}
-
-extension ScreenExtension on Screen {
- GetPage getPage(
- {required GetView Function() page,
- Bindings? binding,
- List bindings = const [],
- List? middlewares,
- List>? children,
- bool preventDuplicates = true,
- Role? role}) {
- // we are injecting the Screen variable here
- pageW() {
- GetView p = page();
- p.screen = this;
- return p;
- }
-
- //check role and screen mapping for rolebased access
- if (accessLevel == AccessLevel.roleBased) {
- if (role == null &&
- (parent == null || parent!.accessLevel != AccessLevel.roleBased)) {
- throw Exception("Role must be provided for RoleBased Screens");
- }
- if (role != null && !role.permissions.contains(this)) {
- throw Exception("Role must permit this Screen");
- }
- }
-
- return _getPage(pageW, binding, bindings, middlewares, children,
- preventDuplicates, role);
- }
-
- GetPage getPages(
- {required GetWidget Function() page,
- Bindings? binding,
- List bindings = const [],
- List? middlewares,
- List>? children,
- bool preventDuplicates = false,
- Role? role}) {
- pageW() {
- GetWidget p = page();
- p.screen = this;
- return p;
- }
-
- return _getPage(pageW, binding, bindings, middlewares, children,
- preventDuplicates, role);
- }
-
- GetPage _getPage(
- Widget Function() pageW,
- Bindings? binding,
- List bindings,
- List? middlewares,
- List>? children,
- bool preventDuplicates,
- Role? role) {
- return binding != null
- ? GetPage(
- preventDuplicates: preventDuplicates,
- middlewares: middlewares ?? defaultMiddlewares(role),
- name: path,
- page: pageW,
- title: label,
- transition: Transition.fade,
- binding: binding,
- children: children ?? const [])
- : GetPage(
- preventDuplicates: preventDuplicates,
- middlewares: middlewares,
- name: path,
- page: pageW,
- title: label,
- transition: Transition.fade,
- bindings: bindings,
- children: children ?? const []);
- }
-
- List? defaultMiddlewares(Role? role) => (parent == null ||
- parent!.accessLevel.index < accessLevel.index)
- ? switch (accessLevel) {
- AccessLevel.public => null,
- AccessLevel.guest => [EnsureAuthOrGuestMiddleware()],
- AccessLevel.authenticated => [EnsureAuthedAndNotGuestMiddleware()],
- AccessLevel.roleBased => [EnsureRoleMiddleware(role ?? Role.buyer)],
- AccessLevel.masked => throw UnimplementedError(), //not for screens
- AccessLevel.secret => throw UnimplementedError(), //not for screens
- AccessLevel.notAuthed => [EnsureNotAuthedOrGuestMiddleware()],
- }
- : null;
-}
-
-extension RoleExtension on Role {
- int getCurrentIndexFromRoute(GetNavConfig? currentRoute) {
- final String? currentLocation = currentRoute?.location;
- int currentIndex = 0;
- if (currentLocation != null) {
- currentIndex =
- tabs.indexWhere((tab) => currentLocation.startsWith(tab.path));
- }
- return (currentIndex > 0) ? currentIndex : 0;
- }
-
- void routeTo(int value, GetDelegate delegate) {
- delegate.toNamed(tabs[value].route, arguments: {'role': this});
- }
-}
+part of 'app_pages.dart';
+
+extension GetViewExtension on GetView {
+ static final _screens = Expando();
+
+ Screen? get screen => _screens[this];
+ set screen(Screen? x) => _screens[this] = x;
+}
+
+extension GetWidgetExtension on GetWidget {
+ static final _screens = Expando();
+
+ Screen? get screen => _screens[this];
+ set screen(Screen? x) => _screens[this] = x;
+}
+
+extension GetPageExtension on GetPage {}
+
+extension ScreenExtension on Screen {
+ GetPage getPage(
+ {required GetView Function() page,
+ Bindings? binding,
+ List bindings = const [],
+ List? middlewares,
+ List>? children,
+ bool preventDuplicates = true,
+ Role? role}) {
+ // we are injecting the Screen variable here
+ pageW() {
+ GetView p = page();
+ p.screen = this;
+ return p;
+ }
+
+ //check role and screen mapping for rolebased access
+ if (accessLevel == AccessLevel.roleBased) {
+ if (role == null &&
+ (parent == null || parent!.accessLevel != AccessLevel.roleBased)) {
+ throw Exception("Role must be provided for RoleBased Screens");
+ }
+ if (role != null && !role.permissions.contains(this)) {
+ throw Exception("Role must permit this Screen");
+ }
+ }
+
+ return _getPage(pageW, binding, bindings, middlewares, children,
+ preventDuplicates, role);
+ }
+
+ GetPage getPages(
+ {required GetWidget Function() page,
+ Bindings? binding,
+ List bindings = const [],
+ List? middlewares,
+ List>? children,
+ bool preventDuplicates = false,
+ Role? role}) {
+ pageW() {
+ GetWidget p = page();
+ p.screen = this;
+ return p;
+ }
+
+ return _getPage(pageW, binding, bindings, middlewares, children,
+ preventDuplicates, role);
+ }
+
+ GetPage _getPage(
+ Widget Function() pageW,
+ Bindings? binding,
+ List bindings,
+ List? middlewares,
+ List>? children,
+ bool preventDuplicates,
+ Role? role) {
+ return binding != null
+ ? GetPage(
+ preventDuplicates: preventDuplicates,
+ middlewares: middlewares ?? defaultMiddlewares(role),
+ name: path,
+ page: pageW,
+ title: label,
+ transition: Transition.fade,
+ binding: binding,
+ children: children ?? const [])
+ : GetPage(
+ preventDuplicates: preventDuplicates,
+ middlewares: middlewares,
+ name: path,
+ page: pageW,
+ title: label,
+ transition: Transition.fade,
+ bindings: bindings,
+ children: children ?? const []);
+ }
+
+ List? defaultMiddlewares(Role? role) => (parent == null ||
+ parent!.accessLevel.index < accessLevel.index)
+ ? switch (accessLevel) {
+ AccessLevel.public => null,
+ AccessLevel.guest => [EnsureAuthOrGuestMiddleware()],
+ AccessLevel.authenticated => [EnsureAuthedAndNotGuestMiddleware()],
+ AccessLevel.roleBased => [EnsureRoleMiddleware(role ?? Role.buyer)],
+ AccessLevel.masked => throw UnimplementedError(), //not for screens
+ AccessLevel.secret => throw UnimplementedError(), //not for screens
+ AccessLevel.notAuthed => [EnsureNotAuthedOrGuestMiddleware()],
+ }
+ : null;
+}
+
+extension RoleExtension on Role {
+ int getCurrentIndexFromRoute(GetNavConfig? currentRoute) {
+ final String? currentLocation = currentRoute?.location;
+ int currentIndex = 0;
+ if (currentLocation != null) {
+ currentIndex =
+ tabs.indexWhere((tab) => currentLocation.startsWith(tab.path));
+ }
+ return (currentIndex > 0) ? currentIndex : 0;
+ }
+
+ void routeTo(int value, GetDelegate delegate) {
+ delegate.toNamed(tabs[value].route, arguments: {'role': this});
+ }
+}
diff --git a/lib/app/widgets/change_password_dialog.dart b/lib/app/widgets/change_password_dialog.dart
index 78c392e5..2c20194b 100644
--- a/lib/app/widgets/change_password_dialog.dart
+++ b/lib/app/widgets/change_password_dialog.dart
@@ -1,3 +1,201 @@
+<<<<<<< HEAD
+// import 'package:firebase_auth/firebase_auth.dart';
+// import 'package:flutter/material.dart';
+// import 'package:get/get.dart';
+//
+// import '../../constants.dart';
+//
+// class ChangePasswordDialog extends StatefulWidget {
+// final User user;
+//
+// ChangePasswordDialog(this.user, {super.key});
+//
+// final _formKey = GlobalKey();
+// final _formValues = FormValues();
+//
+// @override
+// State createState() => _ChangePasswordDialogState();
+//
+// void onSubmit() async {
+// if (_formKey.currentState != null && _formKey.currentState!.validate()) {
+// _formKey.currentState?.save();
+// try {
+// AuthCredential credential = EmailAuthProvider.credential(
+// email: user.email!, password: _formValues.old!);
+// await user.reauthenticateWithCredential(credential);
+// await user.updatePassword(_formValues.newP!);
+// Get.back(result: true);
+// } catch (e) {
+// _formValues.authError = "Incorrect Password";
+// _formKey.currentState!.validate();
+// // Get.snackbar("Error", e.toString());
+// }
+// }
+// }
+//
+// void onReset() {
+// _formKey.currentState?.reset();
+// }
+// }
+//
+// class FormValues {
+// String? old;
+// String? newP;
+// String? authError;
+// }
+//
+// class _ChangePasswordDialogState extends State {
+// @override
+// Widget build(BuildContext context) {
+// return Material(
+// child: Form(
+// key: widget._formKey,
+// child: Column(
+// children: [
+// TextFormField(
+// textInputAction: TextInputAction.done,
+// autovalidateMode: AutovalidateMode.onUserInteraction,
+// obscureText: true,
+// cursorColor: kPrimaryColor,
+// decoration: const InputDecoration(
+// hintText: "Old Password",
+// prefixIcon: Padding(
+// padding: EdgeInsets.all(defaultPadding),
+// child: Icon(Icons.key),
+// ),
+// ),
+// validator: (String? value) {
+// return widget._formValues.authError ??
+// ((value != null && value.length < 8)
+// ? 'Pwd cannot be less than 8 characters'
+// : null);
+// },
+// onChanged: (value) {
+// setState(() {
+// widget._formValues.old = value;
+// widget._formValues.authError = null;
+// });
+// },
+// ),
+// Padding(
+// padding: const EdgeInsets.symmetric(vertical: defaultPadding),
+// child: TextFormField(
+// textInputAction: TextInputAction.done,
+// autovalidateMode: AutovalidateMode.onUserInteraction,
+// obscureText: true,
+// cursorColor: kPrimaryColor,
+// decoration: const InputDecoration(
+// hintText: "New Password",
+// prefixIcon: Padding(
+// padding: EdgeInsets.all(defaultPadding),
+// child: Icon(Icons.lock),
+// ),
+// ),
+// validator: (String? value) {
+// return (value != null && value.length < 8)
+// ? 'Pwd cannot be less than 8 characters'
+// : (value != null && value == widget._formValues.old)
+// ? 'Pwd cannot be same as old Pwd'
+// : null;
+// },
+// onChanged: (value) {
+// setState(() {
+// widget._formValues.newP = value;
+// });
+// },
+// ),
+// ),
+// Padding(
+// padding: const EdgeInsets.symmetric(vertical: defaultPadding),
+// child: TextFormField(
+// textInputAction: TextInputAction.done,
+// autovalidateMode: AutovalidateMode.onUserInteraction,
+// obscureText: true,
+// cursorColor: kPrimaryColor,
+// decoration: const InputDecoration(
+// hintText: "Confirm Password",
+// prefixIcon: Padding(
+// padding: EdgeInsets.all(defaultPadding),
+// child: Icon(Icons.confirmation_num),
+// ),
+// ),
+// validator: (String? value) {
+// return (value != null && value != widget._formValues.newP)
+// ? 'Pwd does not match'
+// : null;
+// },
+// ),
+// ),
+// const SizedBox(height: defaultPadding),
+// ElevatedButton(
+// onPressed: widget.onReset,
+// child: const Text(
+// "Reset",
+// ),
+// ),
+// ],
+// ),
+// ));
+// }
+// }
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+class ChangePasswordController extends GetxController {
+ var currentPassword = ''.obs;
+ var newPassword = ''.obs;
+ var confirmPassword = ''.obs;
+
+ void changePassword() {
+ // Logic for changing the password goes here.
+ if (newPassword.value == confirmPassword.value) {
+ // Perform password change
+ Get.snackbar('Success', 'Password changed successfully!');
+ } else {
+ Get.snackbar('Error', 'Passwords do not match');
+ }
+ }
+}
+
+class ChangePasswordScreen extends StatelessWidget {
+ final ChangePasswordController controller = Get.put(ChangePasswordController());
+
+ // Remove 'const' from the constructor
+ ChangePasswordScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Change Password')),
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ Obx(() => TextField(
+ onChanged: (value) => controller.currentPassword.value = value,
+ decoration: const InputDecoration(labelText: 'Current Password'),
+ obscureText: true,
+ )),
+ Obx(() => TextField(
+ onChanged: (value) => controller.newPassword.value = value,
+ decoration: const InputDecoration(labelText: 'New Password'),
+ obscureText: true,
+ )),
+ Obx(() => TextField(
+ onChanged: (value) => controller.confirmPassword.value = value,
+ decoration: const InputDecoration(labelText: 'Confirm New Password'),
+ obscureText: true,
+ )),
+ const SizedBox(height: 20),
+ ElevatedButton(
+ onPressed: controller.changePassword,
+ child: const Text('Change Password'),
+ ),
+ ],
+ ),
+ ),
+ );
+=======
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -135,5 +333,6 @@ class _ChangePasswordDialogState extends State {
],
),
));
+>>>>>>> origin/main
}
}
diff --git a/lib/app/widgets/image_picker_button.dart b/lib/app/widgets/image_picker_button.dart
index d6e87ff4..69a8840a 100644
--- a/lib/app/widgets/image_picker_button.dart
+++ b/lib/app/widgets/image_picker_button.dart
@@ -1,91 +1,91 @@
-import 'package:file_picker/file_picker.dart';
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import 'package:get_storage/get_storage.dart';
-import 'package:image_picker/image_picker.dart';
-
-import '../../models/action_enum.dart';
-import 'menu_sheet_button.dart';
-
-enum ImageSources implements ActionEnum {
- camera(Icons.camera, 'Camera'),
- gallery(Icons.photo_library, 'Gallery'),
- file(Icons.file_upload, 'File');
-
- const ImageSources(this.icon, this.label);
-
- @override
- Future doAction() async {
- switch (this) {
- case ImageSources.camera:
- return await getImage(ImageSource.camera);
- case ImageSources.gallery:
- return await getImage(ImageSource.gallery);
- case ImageSources.file:
- return await getFile();
- default:
- }
- return null;
- }
-
- @override
- final IconData? icon;
- @override
- final String? label;
-
- static Future getImage(ImageSource imageSource) async {
- final pickedFile = await ImagePicker().pickImage(source: imageSource);
- if (pickedFile != null) {
- return pickedFile.path;
- } else {
- Get.snackbar('Error', 'Image Not Selected');
- return null;
- }
- }
-
- static Future getFile() async {
- FilePickerResult? result = await FilePicker.platform
- .pickFiles(type: FileType.image, allowMultiple: false);
-
- if (result != null && result.files.isNotEmpty) {
- final fileBytes = result.files.first.bytes;
- final fileName = result.files.first.name;
- GetStorage().write(fileName, fileBytes);
-
- return fileName;
- //result.files.single.path;//is causing issues for Web, see https://github.com/miguelpruivo/flutter_file_picker/wiki/FAQ
- } else {
- Get.snackbar('Error', 'Image Not Selected');
- return null;
- }
- }
-}
-
-class ImagePickerButton extends MenuSheetButton {
- final ValueSetter? callback;
-
- const ImagePickerButton(
- {super.key,
- super.icon = const Icon(Icons.image),
- super.label = 'Pick an Image',
- this.callback});
-
- @override
- Iterable get values => ImageSources.values;
-
- @override
- void callbackFunc(act) {
- if (callback != null) callback!(act);
- }
-
- @override
- Widget build(BuildContext context) {
- return !(GetPlatform.isAndroid || GetPlatform.isIOS)
- ? TextButton.icon(
- onPressed: () async => callbackFunc(await ImageSources.getFile()),
- icon: icon,
- label: const Text('Pick an Image'),
- )
- : builder(context);
- }
-}
+import 'package:file_picker/file_picker.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:get_storage/get_storage.dart';
+import 'package:image_picker/image_picker.dart';
+
+import '../../models/action_enum.dart';
+import 'menu_sheet_button.dart';
+
+enum ImageSources implements ActionEnum {
+ camera(Icons.camera, 'Camera'),
+ gallery(Icons.photo_library, 'Gallery'),
+ file(Icons.file_upload, 'File');
+
+ const ImageSources(this.icon, this.label);
+
+ @override
+ Future doAction() async {
+ switch (this) {
+ case ImageSources.camera:
+ return await getImage(ImageSource.camera);
+ case ImageSources.gallery:
+ return await getImage(ImageSource.gallery);
+ case ImageSources.file:
+ return await getFile();
+ default:
+ }
+ return null;
+ }
+
+ @override
+ final IconData? icon;
+ @override
+ final String? label;
+
+ static Future getImage(ImageSource imageSource) async {
+ final pickedFile = await ImagePicker().pickImage(source: imageSource);
+ if (pickedFile != null) {
+ return pickedFile.path;
+ } else {
+ Get.snackbar('Error', 'Image Not Selected');
+ return null;
+ }
+ }
+
+ static Future getFile() async {
+ FilePickerResult? result = await FilePicker.platform
+ .pickFiles(type: FileType.image, allowMultiple: false);
+
+ if (result != null && result.files.isNotEmpty) {
+ final fileBytes = result.files.first.bytes;
+ final fileName = result.files.first.name;
+ GetStorage().write(fileName, fileBytes);
+
+ return fileName;
+ //result.files.single.path;//is causing issues for Web, see https://github.com/miguelpruivo/flutter_file_picker/wiki/FAQ
+ } else {
+ Get.snackbar('Error', 'Image Not Selected');
+ return null;
+ }
+ }
+}
+
+class ImagePickerButton extends MenuSheetButton {
+ final ValueSetter? callback;
+
+ const ImagePickerButton(
+ {super.key,
+ super.icon = const Icon(Icons.image),
+ super.label = 'Pick an Image',
+ this.callback});
+
+ @override
+ Iterable get values => ImageSources.values;
+
+ @override
+ void callbackFunc(act) {
+ if (callback != null) callback!(act);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return !(GetPlatform.isAndroid || GetPlatform.isIOS)
+ ? TextButton.icon(
+ onPressed: () async => callbackFunc(await ImageSources.getFile()),
+ icon: icon,
+ label: const Text('Pick an Image'),
+ )
+ : builder(context);
+ }
+}
diff --git a/lib/app/widgets/login_widgets.dart b/lib/app/widgets/login_widgets.dart
index b8f2d8c1..909cf7f1 100644
--- a/lib/app/widgets/login_widgets.dart
+++ b/lib/app/widgets/login_widgets.dart
@@ -1,95 +1,95 @@
-// ignore_for_file: inference_failure_on_function_invocation
-
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../../services/auth_service.dart';
-import '../../models/screens.dart';
-import '../../services/remote_config.dart';
-import 'menu_sheet_button.dart';
-
-class LoginWidgets {
- static Widget headerBuilder(context, constraints, shrinkOffset) {
- return Padding(
- padding: const EdgeInsets.all(20),
- child: AspectRatio(
- aspectRatio: 1,
- child: Image.asset('assets/images/flutterfire_300x.png'),
- ),
- );
- }
-
- static Widget footerBuilder(myWidget) {
- return Column(
- children: [
- myWidget,
- const Padding(
- padding: EdgeInsets.only(top: 16),
- child: Text(
- 'By signing in, you agree to our terms and conditions.',
- style: TextStyle(color: Colors.grey),
- ))
- ],
- );
- }
-
- static Widget sideBuilder(context, shrinkOffset) {
- return Padding(
- padding: const EdgeInsets.all(20),
- child: AspectRatio(
- aspectRatio: 1,
- child: Image.asset('assets/images/flutterfire_300x.png'),
- ),
- );
- }
-}
-
-class LoginBottomSheetToggle extends MenuSheetButton {
- const LoginBottomSheetToggle(this.current, {super.key});
- final GetNavConfig current;
-
- @override
- Iterable get values {
- MenuItemsController controller = Get.find();
- return controller.values.value;
- }
-
- @override
- Icon? get icon => (AuthService.to.isLoggedInValue)
- ? values.length == 1
- ? const Icon(Icons.logout)
- : const Icon(Icons.menu)
- : const Icon(Icons.login);
-
- @override
- String? get label => (AuthService.to.isLoggedInValue)
- ? values.length == 1
- ? 'Logout'
- : 'Click for Options'
- : 'Login';
-
- @override
- Widget build(BuildContext context) {
- MenuItemsController controller = Get.put(
- MenuItemsController([]),
- permanent: true); //must make true else gives error
- Screen.sheet(null).then((val) {
- controller.values.value = val;
- });
- RemoteConfig.instance.then((ins) =>
- ins.addUseBottomSheetForProfileOptionsListener((val) async =>
- {controller.values.value = await Screen.sheet(null)}));
- return Obx(() => (AuthService.to.isLoggedInValue)
- ? builder(context, vals: controller.values.value)
- : !(current.currentPage!.name == Screen.LOGIN.path)
- ? IconButton(
- onPressed: () async {
- await Screen.LOGIN.doAction();
- // controller.toggle(Screen.LOGIN);
- },
- icon: Icon(Screen.LOGIN.icon),
- tooltip: Screen.LOGIN.label,
- )
- : const SizedBox.shrink()); //should be only for loggedin case
- }
-}
+// ignore_for_file: inference_failure_on_function_invocation
+
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../../services/auth_service.dart';
+import '../../models/screens.dart';
+import '../../services/remote_config.dart';
+import 'menu_sheet_button.dart';
+
+class LoginWidgets {
+ static Widget headerBuilder(context, constraints, shrinkOffset) {
+ return Padding(
+ padding: const EdgeInsets.all(20),
+ child: AspectRatio(
+ aspectRatio: 1,
+ child: Image.asset('assets/images/flutterfire_300x.png'),
+ ),
+ );
+ }
+
+ static Widget footerBuilder(myWidget) {
+ return Column(
+ children: [
+ myWidget,
+ const Padding(
+ padding: EdgeInsets.only(top: 16),
+ child: Text(
+ 'By signing in, you agree to our terms and conditions.',
+ style: TextStyle(color: Colors.grey),
+ ))
+ ],
+ );
+ }
+
+ static Widget sideBuilder(context, shrinkOffset) {
+ return Padding(
+ padding: const EdgeInsets.all(20),
+ child: AspectRatio(
+ aspectRatio: 1,
+ child: Image.asset('assets/images/flutterfire_300x.png'),
+ ),
+ );
+ }
+}
+
+class LoginBottomSheetToggle extends MenuSheetButton {
+ const LoginBottomSheetToggle(this.current, {super.key});
+ final GetNavConfig current;
+
+ @override
+ Iterable get values {
+ MenuItemsController controller = Get.find();
+ return controller.values.value;
+ }
+
+ @override
+ Icon? get icon => (AuthService.to.isLoggedInValue)
+ ? values.length == 1
+ ? const Icon(Icons.logout)
+ : const Icon(Icons.menu)
+ : const Icon(Icons.login);
+
+ @override
+ String? get label => (AuthService.to.isLoggedInValue)
+ ? values.length == 1
+ ? 'Logout'
+ : 'Click for Options'
+ : 'Login';
+
+ @override
+ Widget build(BuildContext context) {
+ MenuItemsController controller = Get.put(
+ MenuItemsController([]),
+ permanent: true); //must make true else gives error
+ Screen.sheet(null).then((val) {
+ controller.values.value = val;
+ });
+ RemoteConfig.instance.then((ins) =>
+ ins.addUseBottomSheetForProfileOptionsListener((val) async =>
+ {controller.values.value = await Screen.sheet(null)}));
+ return Obx(() => (AuthService.to.isLoggedInValue)
+ ? builder(context, vals: controller.values.value)
+ : !(current.currentPage!.name == Screen.LOGIN.path)
+ ? IconButton(
+ onPressed: () async {
+ await Screen.LOGIN.doAction();
+ // controller.toggle(Screen.LOGIN);
+ },
+ icon: Icon(Screen.LOGIN.icon),
+ tooltip: Screen.LOGIN.label,
+ )
+ : const SizedBox.shrink()); //should be only for loggedin case
+ }
+}
diff --git a/lib/app/widgets/menu_sheet_button.dart b/lib/app/widgets/menu_sheet_button.dart
index abd3873e..51d0f15c 100644
--- a/lib/app/widgets/menu_sheet_button.dart
+++ b/lib/app/widgets/menu_sheet_button.dart
@@ -1,94 +1,94 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../../models/action_enum.dart';
-
-class MenuItemsController extends GetxController {
- MenuItemsController(Iterable iter) : values = Rx>(iter);
-
- final Rx> values;
-}
-
-class MenuSheetButton extends StatelessWidget {
- final Iterable? values_;
- final Icon? icon;
- final String? label;
-
- const MenuSheetButton(
- {super.key,
- this.values_,
- this.icon,
- this.label}); //passing scaffoldKey means that bottomSheet is added to it
-
- Iterable get values => values_!;
-
- static Widget bottomSheet(
- Iterable values, ValueSetter? callback) {
- return SizedBox(
- height: 180,
- width: Get.mediaQuery.size.width,
- child: ListView(
- // mainAxisAlignment: MainAxisAlignment.center,
- children: values
- .map(
- (ActionEnum value) => ListTile(
- leading: Icon(value.icon),
- title: Text(
- value.label!,
- ),
- onTap: () async {
- Get.back();
- callback != null
- ? callback(await value.doAction())
- : await value.doAction();
- }),
- )
- .toList(),
- ),
- );
- }
-
- List> getItems(BuildContext context, Iterable values) {
- return values.map>(createPopupMenuItem).toList();
- }
-
- PopupMenuEntry createPopupMenuItem(dynamic value) => PopupMenuItem(
- value: value,
- child: Text(value.label ?? ''), //TODO add Icon
- );
-
- @override
- Widget build(BuildContext context) {
- return builder(context);
- }
-
-//This should be a modal bottom sheet if on Mobile (See https://mercyjemosop.medium.com/select-and-upload-images-to-firebase-storage-flutter-6fac855970a9)
- Widget builder(BuildContext context, {Iterable? vals}) {
- Iterable values = vals ?? values_!;
- return values.length == 1 ||
- Get.mediaQuery.orientation == Orientation.portrait
- // : Get.context!.isPortrait
- ? (icon != null
- ? IconButton(
- onPressed: () => buttonPressed(values),
- icon: icon!,
- tooltip: label,
- )
- : TextButton(
- onPressed: () => buttonPressed(values),
- child: Text(label ?? 'Need Label')))
- : PopupMenuButton(
- itemBuilder: (context_) => getItems(context_, values),
- icon: icon,
- tooltip: label,
- onSelected: (T value) async =>
- callbackFunc(await value.doAction()));
- }
-
- void buttonPressed(Iterable values) async => values.length == 1
- ? callbackFunc(await values.first.doAction())
- : Get.bottomSheet(MenuSheetButton.bottomSheet(values, callbackFunc),
- backgroundColor: Colors.white);
-
- void callbackFunc(act) {}
-}
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../../models/action_enum.dart';
+
+class MenuItemsController extends GetxController {
+ MenuItemsController(Iterable iter) : values = Rx>(iter);
+
+ final Rx> values;
+}
+
+class MenuSheetButton extends StatelessWidget {
+ final Iterable? values_;
+ final Icon? icon;
+ final String? label;
+
+ const MenuSheetButton(
+ {super.key,
+ this.values_,
+ this.icon,
+ this.label}); //passing scaffoldKey means that bottomSheet is added to it
+
+ Iterable get values => values_!;
+
+ static Widget bottomSheet(
+ Iterable values, ValueSetter? callback) {
+ return SizedBox(
+ height: 180,
+ width: Get.mediaQuery.size.width,
+ child: ListView(
+ // mainAxisAlignment: MainAxisAlignment.center,
+ children: values
+ .map(
+ (ActionEnum value) => ListTile(
+ leading: Icon(value.icon),
+ title: Text(
+ value.label!,
+ ),
+ onTap: () async {
+ Get.back();
+ callback != null
+ ? callback(await value.doAction())
+ : await value.doAction();
+ }),
+ )
+ .toList(),
+ ),
+ );
+ }
+
+ List> getItems(BuildContext context, Iterable values) {
+ return values.map>(createPopupMenuItem).toList();
+ }
+
+ PopupMenuEntry createPopupMenuItem(dynamic value) => PopupMenuItem(
+ value: value,
+ child: Text(value.label ?? ''), //TODO add Icon
+ );
+
+ @override
+ Widget build(BuildContext context) {
+ return builder(context);
+ }
+
+//This should be a modal bottom sheet if on Mobile (See https://mercyjemosop.medium.com/select-and-upload-images-to-firebase-storage-flutter-6fac855970a9)
+ Widget builder(BuildContext context, {Iterable? vals}) {
+ Iterable values = vals ?? values_!;
+ return values.length == 1 ||
+ Get.mediaQuery.orientation == Orientation.portrait
+ // : Get.context!.isPortrait
+ ? (icon != null
+ ? IconButton(
+ onPressed: () => buttonPressed(values),
+ icon: icon!,
+ tooltip: label,
+ )
+ : TextButton(
+ onPressed: () => buttonPressed(values),
+ child: Text(label ?? 'Need Label')))
+ : PopupMenuButton(
+ itemBuilder: (context_) => getItems(context_, values),
+ icon: icon,
+ tooltip: label,
+ onSelected: (T value) async =>
+ callbackFunc(await value.doAction()));
+ }
+
+ void buttonPressed(Iterable values) async => values.length == 1
+ ? callbackFunc(await values.first.doAction())
+ : Get.bottomSheet(MenuSheetButton.bottomSheet(values, callbackFunc),
+ backgroundColor: Colors.white);
+
+ void callbackFunc(act) {}
+}
diff --git a/lib/app/widgets/screen_widget.dart b/lib/app/widgets/screen_widget.dart
index d80c9275..98eb46d1 100644
--- a/lib/app/widgets/screen_widget.dart
+++ b/lib/app/widgets/screen_widget.dart
@@ -1,75 +1,75 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import '../routes/app_pages.dart';
-import '../../models/role.dart';
-import '../../models/screens.dart';
-
-class ScreenWidget extends StatelessWidget {
- final Widget body;
- final Role? role;
-
- final GetDelegate? delegate;
-
- final GetNavConfig? currentRoute;
-
- final Screen screen;
- final AppBar? appBar;
-
- const ScreenWidget({
- super.key,
- required this.body,
- required this.screen,
- this.role = Role.buyer,
- this.delegate,
- this.currentRoute,
- this.appBar,
- });
-
- @override
- Widget build(BuildContext context) {
- int currentIndex =
- role != null ? role!.getCurrentIndexFromRoute(currentRoute) : 0;
- Iterable fabs = screen.fabs;
- return Scaffold(
- body: body,
- appBar: appBar,
- bottomNavigationBar: (screen.navTabs.isNotEmpty)
- ? BottomNavigationBar(
- currentIndex: currentIndex,
- onTap: (value) {
- if (delegate != null) {
- role!.routeTo(value, delegate!);
- }
- },
- items:
- role!.tabs //screen may have more navTabs but we need by role
- .map((Screen tab) => BottomNavigationBarItem(
- icon: Icon(tab.icon),
- label: tab.label,
- ))
- .toList(),
- )
- : null,
- floatingActionButton: fabs.isNotEmpty ? getFAB(fabs) : null,
- // bottomSheet: //this is used for persistent bar like status bar
- );
- }
-
- FloatingActionButton? getFAB(Iterable fabs) {
- if (fabs.length == 1) {
- var screen = fabs.firstOrNull!;
- return FloatingActionButton.extended(
- backgroundColor: Colors.blue,
- onPressed: () => Get.rootDelegate.toNamed(screen.route),
- label: Text(screen.label ?? ''),
- icon: screen.icon == null
- ? null
- : Icon(
- screen.icon,
- color: Colors.white,
- ),
- );
- }
- return null; //TODO multi fab button on press
- }
-}
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import '../routes/app_pages.dart';
+import '../../models/role.dart';
+import '../../models/screens.dart';
+
+class ScreenWidget extends StatelessWidget {
+ final Widget body;
+ final Role? role;
+
+ final GetDelegate? delegate;
+
+ final GetNavConfig? currentRoute;
+
+ final Screen screen;
+ final AppBar? appBar;
+
+ const ScreenWidget({
+ super.key,
+ required this.body,
+ required this.screen,
+ this.role = Role.buyer,
+ this.delegate,
+ this.currentRoute,
+ this.appBar,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ int currentIndex =
+ role != null ? role!.getCurrentIndexFromRoute(currentRoute) : 0;
+ Iterable fabs = screen.fabs;
+ return Scaffold(
+ body: body,
+ appBar: appBar,
+ bottomNavigationBar: (screen.navTabs.isNotEmpty)
+ ? BottomNavigationBar(
+ currentIndex: currentIndex,
+ onTap: (value) {
+ if (delegate != null) {
+ role!.routeTo(value, delegate!);
+ }
+ },
+ items:
+ role!.tabs //screen may have more navTabs but we need by role
+ .map((Screen tab) => BottomNavigationBarItem(
+ icon: Icon(tab.icon),
+ label: tab.label,
+ ))
+ .toList(),
+ )
+ : null,
+ floatingActionButton: fabs.isNotEmpty ? getFAB(fabs) : null,
+ // bottomSheet: //this is used for persistent bar like status bar
+ );
+ }
+
+ FloatingActionButton? getFAB(Iterable fabs) {
+ if (fabs.length == 1) {
+ var screen = fabs.firstOrNull!;
+ return FloatingActionButton.extended(
+ backgroundColor: Colors.blue,
+ onPressed: () => Get.rootDelegate.toNamed(screen.route),
+ label: Text(screen.label ?? ''),
+ icon: screen.icon == null
+ ? null
+ : Icon(
+ screen.icon,
+ color: Colors.white,
+ ),
+ );
+ }
+ return null; //TODO multi fab button on press
+ }
+}
diff --git a/lib/constants.dart b/lib/constants.dart
index dd5d17ce..33f97183 100644
--- a/lib/constants.dart
+++ b/lib/constants.dart
@@ -1,21 +1,21 @@
-import 'package:flutter/material.dart';
-// import 'package:get/get_utils/src/platform/platform.dart';
-
-const kPrimaryColor = Color(0xFF6F35A5);
-const kPrimaryLightColor = Color(0xFFF1E6FF);
-
-const double defaultPadding = 16.0;
-
-const useEmulator = false;
-
-const useRecaptcha = false;
-
-const sendMailFromClient =
- true; // set this true if in server using custom claim status
-
-const emulatorHost =
- "127.0.0.1"; // GetPlatform.isAndroid ? "10.0.2.2" : "127.0.0.1"; //This is not required due to automaticHostMapping
-
-const baseUrl = useEmulator ? "http://127.0.0.1" : "your domain";
-
-const bundleID = "com.example";
+import 'package:flutter/material.dart';
+// import 'package:get/get_utils/src/platform/platform.dart';
+
+const kPrimaryColor = Color(0xFF6F35A5);
+const kPrimaryLightColor = Color(0xFFF1E6FF);
+
+const double defaultPadding = 16.0;
+
+const useEmulator = false;
+
+const useRecaptcha = false;
+
+const sendMailFromClient =
+ true; // set this true if in server using custom claim status
+
+const emulatorHost =
+ "127.0.0.1"; // GetPlatform.isAndroid ? "10.0.2.2" : "127.0.0.1"; //This is not required due to automaticHostMapping
+
+const baseUrl = useEmulator ? "http://127.0.0.1" : "your domain";
+
+const bundleID = "com.example";
diff --git a/lib/controllers/auth_controller.dart b/lib/controllers/auth_controller.dart
new file mode 100644
index 00000000..e9ea3ee7
--- /dev/null
+++ b/lib/controllers/auth_controller.dart
@@ -0,0 +1,16 @@
+import 'package:get/get.dart';
+
+class AuthController extends GetxController {
+ final phoneNumber = ''.obs;
+ final smsCode = ''.obs;
+
+ void sendSmsCode() {
+ // Logic to send SMS code
+ Get.snackbar('Success', 'SMS code sent!');
+ }
+
+ void verifySmsCode() {
+ // Logic to verify SMS code and complete login
+ Get.snackbar('Success', 'Phone number verified!');
+ }
+}
diff --git a/lib/controllers/recaptcha_controller.dart b/lib/controllers/recaptcha_controller.dart
new file mode 100644
index 00000000..73754355
--- /dev/null
+++ b/lib/controllers/recaptcha_controller.dart
@@ -0,0 +1,10 @@
+import 'package:get/get.dart';
+
+class ReCaptchaController extends GetxController {
+ final isVerified = false.obs;
+
+ void verifyRecaptcha() {
+ // Logic for ReCaptcha verification
+ isVerified.value = true;
+ }
+}
diff --git a/lib/controllers/reset_password_controller.dart b/lib/controllers/reset_password_controller.dart
new file mode 100644
index 00000000..9f83a69a
--- /dev/null
+++ b/lib/controllers/reset_password_controller.dart
@@ -0,0 +1,15 @@
+import 'package:get/get.dart';
+
+class ResetPasswordController extends GetxController {
+ final email = ''.obs;
+
+ void sendPasswordResetEmail() {
+ // Logic for sending reset email
+ Get.snackbar('Success', 'Password reset email sent!');
+ }
+
+ void verifyEmail() {
+ // Logic for email verification
+ Get.snackbar('Success', 'Email verified successfully!');
+ }
+}
diff --git a/lib/firebase_options.template b/lib/firebase_options.template
index 57f5e36d..13c86332 100644
--- a/lib/firebase_options.template
+++ b/lib/firebase_options.template
@@ -1,96 +1,96 @@
-// This is a template of the file generated by FlutterFire CLI.
-// Actual file will be .dart extension
-// ignore_for_file: type=lint
-import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
-import 'package:firebase_storage/firebase_storage.dart';
-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 DefaultFirebaseOptions {
- 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: 'YOUR_API_KEY',
- appId: 'YOUR_APP_ID',
- messagingSenderId: 'YOUR_MESSAGING_ID',
- projectId: 'YOUR_PROJECT_ID',
- authDomain: 'YOUR_PROJECT_ID.firebaseapp.com',
- storageBucket: 'YOUR_PROJECT_ID.appspot.com',
- measurementId: 'YOUR_MEASUREMENT_ID',
- );
-
- static const String webClientId =
- 'YOUR_APP_ID.apps.googleusercontent.com';
-
- static const FirebaseOptions android = FirebaseOptions(
- apiKey: 'YOUR_APP_ID',
- appId: 'YOUR_APP_ID',
- messagingSenderId: 'YOUR_MESSAGING_ID',
- projectId: 'YOUR_PROJECT_ID',
- storageBucket: 'YOUR_PROJECT_ID.appspot.com',
- );
-
- static const FirebaseOptions ios = FirebaseOptions(
- apiKey: 'YOUR_API_KEY',
- appId: 'YOUR_APP_ID',
- messagingSenderId: 'YOUR_MESSAGING_ID',
- projectId: 'YOUR_PROJECT_ID',
- storageBucket: 'YOUR_PROJECT_ID.appspot.com',
- iosBundleId: 'com.example.complete',
- );
-
- static const FirebaseOptions macos = FirebaseOptions(
- apiKey: 'YOUR_API_KEY',
- appId: 'YOUR_APP_ID',
- messagingSenderId: 'YOUR_MESSAGING_ID',
- projectId: 'YOUR_PROJECT_ID',
- storageBucket: 'YOUR_PROJECT_ID.appspot.com',
- iosBundleId: 'com.example.complete',
- );
-
- static const FirebaseOptions windows = FirebaseOptions(
- apiKey: 'YOUR_API_KEY',
- appId: 'YOUR_APP_ID',
- messagingSenderId: 'YOUR_MESSAGING_ID',
- projectId: 'YOUR_PROJECT_ID',
- authDomain: 'YOUR_PROJECT_ID.firebaseapp.com',
- storageBucket: 'YOUR_PROJECT_ID.appspot.com',
- measurementId: 'YOUR_MEASUREMENT_ID',
- );
-
- final storage =
- FirebaseStorage.instanceFor(bucket: "gs://YOUR_PROJECT_ID.appspot.com");
-}
+// This is a template of the file generated by FlutterFire CLI.
+// Actual file will be .dart extension
+// ignore_for_file: type=lint
+import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
+import 'package:firebase_storage/firebase_storage.dart';
+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 DefaultFirebaseOptions {
+ 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: 'YOUR_API_KEY',
+ appId: 'YOUR_APP_ID',
+ messagingSenderId: 'YOUR_MESSAGING_ID',
+ projectId: 'YOUR_PROJECT_ID',
+ authDomain: 'YOUR_PROJECT_ID.firebaseapp.com',
+ storageBucket: 'YOUR_PROJECT_ID.appspot.com',
+ measurementId: 'YOUR_MEASUREMENT_ID',
+ );
+
+ static const String webClientId =
+ 'YOUR_APP_ID.apps.googleusercontent.com';
+
+ static const FirebaseOptions android = FirebaseOptions(
+ apiKey: 'YOUR_APP_ID',
+ appId: 'YOUR_APP_ID',
+ messagingSenderId: 'YOUR_MESSAGING_ID',
+ projectId: 'YOUR_PROJECT_ID',
+ storageBucket: 'YOUR_PROJECT_ID.appspot.com',
+ );
+
+ static const FirebaseOptions ios = FirebaseOptions(
+ apiKey: 'YOUR_API_KEY',
+ appId: 'YOUR_APP_ID',
+ messagingSenderId: 'YOUR_MESSAGING_ID',
+ projectId: 'YOUR_PROJECT_ID',
+ storageBucket: 'YOUR_PROJECT_ID.appspot.com',
+ iosBundleId: 'com.example.complete',
+ );
+
+ static const FirebaseOptions macos = FirebaseOptions(
+ apiKey: 'YOUR_API_KEY',
+ appId: 'YOUR_APP_ID',
+ messagingSenderId: 'YOUR_MESSAGING_ID',
+ projectId: 'YOUR_PROJECT_ID',
+ storageBucket: 'YOUR_PROJECT_ID.appspot.com',
+ iosBundleId: 'com.example.complete',
+ );
+
+ static const FirebaseOptions windows = FirebaseOptions(
+ apiKey: 'YOUR_API_KEY',
+ appId: 'YOUR_APP_ID',
+ messagingSenderId: 'YOUR_MESSAGING_ID',
+ projectId: 'YOUR_PROJECT_ID',
+ authDomain: 'YOUR_PROJECT_ID.firebaseapp.com',
+ storageBucket: 'YOUR_PROJECT_ID.appspot.com',
+ measurementId: 'YOUR_MEASUREMENT_ID',
+ );
+
+ final storage =
+ FirebaseStorage.instanceFor(bucket: "gs://YOUR_PROJECT_ID.appspot.com");
+}
diff --git a/lib/main.dart b/lib/main.dart
index 30c258f2..76ae9d9c 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,3 +1,224 @@
+<<<<<<< HEAD
+// // ignore_for_file: inference_failure_on_instance_creation
+//
+// import 'package:firebase_core/firebase_core.dart';
+// import 'package:flutter/material.dart';
+// import 'package:get/get.dart';
+// import 'package:get_storage/get_storage.dart';
+//
+// import 'app/routes/app_pages.dart';
+// import 'services/auth_service.dart';
+//
+// void main() async {
+// WidgetsFlutterBinding.ensureInitialized();
+// await GetStorage.init();
+// await Firebase.initializeApp(
+// options: DefaultFirebaseOptions.currentPlatform,
+// );
+//
+// runApp(
+// GetMaterialApp.router(
+// debugShowCheckedModeBanner:
+// false, //the debug banner will automatically disappear in prod build
+// title: 'Application',
+// initialBinding: BindingsBuilder(
+// () {
+// Get.put(AuthService());
+// },
+// ),
+// getPages: AppPages.routes,
+// // routeInformationParser: GetInformationParser(
+// // // initialRoute: Routes.HOME,
+// // ),
+// // routerDelegate: GetDelegate(
+// // backButtonPopMode: PopMode.History,
+// // preventDuplicateHandlingMode:
+// // PreventDuplicateHandlingMode.ReorderRoutes,
+// // ),
+// theme: ThemeData(
+// highlightColor: Colors.black.withOpacity(0.5),
+// bottomSheetTheme:
+// const BottomSheetThemeData(surfaceTintColor: Colors.blue)),
+// ),
+// );
+// }
+// import 'package:firebase_core/firebase_core.dart';
+// import 'package:flutter/foundation.dart';
+// import 'package:flutter/material.dart';
+// import 'package:get/get.dart';
+// import 'package:get_flutter_fire/screen/responsive_layout.dart';
+//
+// // void main() {
+// // runApp(const MyApp());
+// // }
+// Future main() async{
+// WidgetsFlutterBinding.ensureInitialized();
+// if(kIsWeb){
+// await Firebase.initializeApp(options: FirebaseOptions(apiKey: 'AIzaSyC3XwOe8FpQmq6pELForbSQ-S59RqQDDgA', appId: '1:1071039837988:web:496460b0f356fa8aebe5b1', messagingSenderId: '1071039837988', projectId: 'getflutterfire-96270'));
+// //await Firebase.initializeApp(options: FirebaseOptions(apiKey: AIzaSyC3XwOe8FpQmq6pELForbSQ-S59RqQDDgA, appId: 1:1071039837988:web:49
+// }
+// await Firebase.initializeApp();
+// runApp(MyApp());
+// }
+//
+//
+// class MyApp extends StatelessWidget {
+// const MyApp({super.key});
+//
+// @override
+// Widget build(BuildContext context) {
+// return GetMaterialApp(
+// title: 'Flutter App',
+// theme: ThemeData(
+// brightness: Brightness.light,
+// primarySwatch: Colors.blue,
+// ),
+// darkTheme: ThemeData(
+// brightness: Brightness.dark,
+// ),
+// themeMode: ThemeMode.system,
+// home: const ResponsiveLayout(
+// mobileLayout: MobileHomeScreen(),
+// tabletLayout: TabletHomeScreen(),
+// desktopLayout: DesktopHomeScreen(),
+// ),
+// );
+// }
+// }
+//
+// class MobileHomeScreen extends StatelessWidget {
+// const MobileHomeScreen({super.key});
+//
+// @override
+// Widget build(BuildContext context) {
+// return Scaffold(
+// appBar: AppBar(title: const Text('Mobile Home')),
+// body: const Center(child: Text('Mobile Layout')),
+// );
+// }
+// }
+//
+// class TabletHomeScreen extends StatelessWidget {
+// const TabletHomeScreen({super.key});
+//
+// @override
+// Widget build(BuildContext context) {
+// return Scaffold(
+// appBar: AppBar(title: const Text('Tablet Home')),
+// body: const Center(child: Text('Tablet Layout')),
+// );
+// }
+// }
+//
+// class DesktopHomeScreen extends StatelessWidget {
+// const DesktopHomeScreen({super.key});
+//
+// @override
+// Widget build(BuildContext context) {
+// return Scaffold(
+// appBar: AppBar(title: const Text('Desktop Home')),
+// body: const Center(child: Text('Desktop Layout')),
+// );
+// }
+// }
+
+
+
+import 'package:firebase_core/firebase_core.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'app/routes/app_pages.dart';
+// import 'app/routes/app_routes.dart'; // Import the routes
+import 'package:get_flutter_fire/screen/responsive_layout.dart';
+
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+
+ if (kIsWeb) {
+ // Initialize Firebase for the web
+ await Firebase.initializeApp(
+ options: FirebaseOptions(
+ apiKey: 'AIzaSyC3XwOe8FpQmq6pELForbSQ-S59RqQDDgA',
+ appId: '1:1071039837988:web:496460b0f356fa8aebe5b1',
+ messagingSenderId: '1071039837988',
+ projectId: 'getflutterfire-96270',
+ ),
+ );
+ } else {
+ // Initialize Firebase for mobile
+ await Firebase.initializeApp();
+ }
+
+ runApp(const MyApp());
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return GetMaterialApp(
+ title: 'Flutter App',
+ theme: ThemeData(
+ brightness: Brightness.light,
+ primarySwatch: Colors.blue,
+ ),
+ darkTheme: ThemeData(
+ brightness: Brightness.dark,
+ ),
+ themeMode: ThemeMode.system,
+
+ // Set the initial route
+ initialRoute: AppRoutes.INITIAL,
+
+ // Define the routes
+ getPages: AppRoutes.routes,
+
+ home: const ResponsiveLayout(
+ mobileLayout: MobileHomeScreen(),
+ tabletLayout: TabletHomeScreen(),
+ desktopLayout: DesktopHomeScreen(),
+ ),
+ );
+ }
+}
+
+class MobileHomeScreen extends StatelessWidget {
+ const MobileHomeScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Mobile Home')),
+ body: const Center(child: Text('Mobile Layout')),
+ );
+ }
+}
+
+class TabletHomeScreen extends StatelessWidget {
+ const TabletHomeScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Tablet Home')),
+ body: const Center(child: Text('Tablet Layout')),
+ );
+ }
+}
+
+class DesktopHomeScreen extends StatelessWidget {
+ const DesktopHomeScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Desktop Home')),
+ body: const Center(child: Text('Desktop Layout')),
+ );
+ }
+=======
// ignore_for_file: inference_failure_on_instance_creation
import 'package:firebase_core/firebase_core.dart';
@@ -41,4 +262,5 @@ void main() async {
const BottomSheetThemeData(surfaceTintColor: Colors.blue)),
),
);
+>>>>>>> origin/main
}
diff --git a/lib/models/access_level.dart b/lib/models/access_level.dart
index a7b89742..938eee8e 100644
--- a/lib/models/access_level.dart
+++ b/lib/models/access_level.dart
@@ -1,9 +1,9 @@
-enum AccessLevel {
- public, //available without any login
- guest, //available with guest login
- notAuthed, // used for login screens
- authenticated, //available on login
- roleBased, //available on login and with allowed roles
- masked, //available in a partly masked manner based on role
- secret //never visible
-}
+enum AccessLevel {
+ public, //available without any login
+ guest, //available with guest login
+ notAuthed, // used for login screens
+ authenticated, //available on login
+ roleBased, //available on login and with allowed roles
+ masked, //available in a partly masked manner based on role
+ secret //never visible
+}
diff --git a/lib/models/action_enum.dart b/lib/models/action_enum.dart
index 023adba5..e3a32adf 100644
--- a/lib/models/action_enum.dart
+++ b/lib/models/action_enum.dart
@@ -1,7 +1,7 @@
-import 'package:flutter/material.dart';
-
-abstract class ActionEnum {
- Future doAction();
- IconData? get icon;
- String? get label;
-}
+import 'package:flutter/material.dart';
+
+abstract class ActionEnum {
+ Future doAction();
+ IconData? get icon;
+ String? get label;
+}
diff --git a/lib/models/product.dart b/lib/models/product.dart
index 003d5785..0ed40884 100644
--- a/lib/models/product.dart
+++ b/lib/models/product.dart
@@ -1,9 +1,9 @@
-class Product {
- final String name;
- final String id;
-
- Product({
- required this.name,
- required this.id,
- });
-}
+class Product {
+ final String name;
+ final String id;
+
+ Product({
+ required this.name,
+ required this.id,
+ });
+}
diff --git a/lib/models/role.dart b/lib/models/role.dart
index 50ee31b4..b5a5463f 100644
--- a/lib/models/role.dart
+++ b/lib/models/role.dart
@@ -1,35 +1,35 @@
-import 'screens.dart';
-
-// First tab for all except Admin is Home/Dashboard which is diferrent for each role
-// Admin is User List By Roles with slide to Change Role or Disable
-// Second tab for
-// Guest & Buyer is Public Product List by Category with Slide to Add to Cart
-// Seller is Product List by Category with Add Product FAB leading to Product Form
-// Admin is Category List with Add Category FAB
-// Third tab for
-// Guest is Cart with Guest Auth
-// Buyer is Cart with own Auth
-// Seller is MyProducts
-// Admin is Tasks/Approvals
-// Profile and Settings is in Drawer
-
-enum Role {
- buyer([Screen.DASHBOARD, Screen.PRODUCTS, Screen.CART]),
- seller([Screen.DASHBOARD, Screen.PRODUCTS, Screen.MY_PRODUCTS]),
- admin([Screen.USERS, Screen.CATEGORIES, Screen.TASKS]);
-//higher role can assume a lower role
-
- const Role(this.permissions);
- final List
- permissions; //list of screens, with accessLevel = roleBased, visible for the role
-
- static Role fromString(String? name) => (name != null
- ? Role.values.firstWhere((role) => role.name == name)
- : Role.buyer);
- bool hasAccess(Role role) => index >= role.index;
- bool hasAccessOf(String role) => index >= fromString(role).index;
-
- List get tabs => permissions
- .where((screen) => screen.accessor_ == AccessedVia.navigator)
- .toList(); //the ones in tab
-}
+import 'screens.dart';
+
+// First tab for all except Admin is Home/Dashboard which is diferrent for each role
+// Admin is User List By Roles with slide to Change Role or Disable
+// Second tab for
+// Guest & Buyer is Public Product List by Category with Slide to Add to Cart
+// Seller is Product List by Category with Add Product FAB leading to Product Form
+// Admin is Category List with Add Category FAB
+// Third tab for
+// Guest is Cart with Guest Auth
+// Buyer is Cart with own Auth
+// Seller is MyProducts
+// Admin is Tasks/Approvals
+// Profile and Settings is in Drawer
+
+enum Role {
+ buyer([Screen.DASHBOARD, Screen.PRODUCTS, Screen.CART]),
+ seller([Screen.DASHBOARD, Screen.PRODUCTS, Screen.MY_PRODUCTS]),
+ admin([Screen.USERS, Screen.CATEGORIES, Screen.TASKS]);
+//higher role can assume a lower role
+
+ const Role(this.permissions);
+ final List
+ permissions; //list of screens, with accessLevel = roleBased, visible for the role
+
+ static Role fromString(String? name) => (name != null
+ ? Role.values.firstWhere((role) => role.name == name)
+ : Role.buyer);
+ bool hasAccess(Role role) => index >= role.index;
+ bool hasAccessOf(String role) => index >= fromString(role).index;
+
+ List get tabs => permissions
+ .where((screen) => screen.accessor_ == AccessedVia.navigator)
+ .toList(); //the ones in tab
+}
diff --git a/lib/models/screens.dart b/lib/models/screens.dart
index 24dee39f..d142bcd5 100644
--- a/lib/models/screens.dart
+++ b/lib/models/screens.dart
@@ -1,177 +1,177 @@
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import '../app/widgets/login_widgets.dart';
-import '../services/remote_config.dart';
-import 'action_enum.dart';
-import 'access_level.dart';
-import '../../services/auth_service.dart';
-
-enum AccessedVia {
- auto,
- widget, //example: top right button
- navigator, //bottom nav. can be linked to drawer items //handled in ScreenWidget
- drawer, //creates nav tree //handled in RootView
- bottomSheet, //context menu for web handled via the Button that calls the sheet
- fab, //handled in ScreenWidget
- singleTap, //when an item of a list is clicked
- longTap //or double click
-}
-
-enum Screen implements ActionEnum {
- HOME('/home',
- icon: Icons.home,
- label: "Home",
- accessor_: AccessedVia.drawer,
- accessLevel: AccessLevel.public), //first screen is default screen
- DASHBOARD('/dashboard',
- icon: Icons.home,
- label: "Home",
- accessor_: AccessedVia.navigator,
- accessLevel: AccessLevel.public,
- parent: HOME),
- PRODUCTS('/products',
- icon: Icons.dataset,
- label: "Products",
- accessor_: AccessedVia.navigator,
- accessLevel: AccessLevel.public,
- parent: HOME),
- PRODUCT_DETAILS('/:productId',
- accessLevel: AccessLevel.public, parent: PRODUCTS),
- LOGIN('/login',
- icon: Icons.login,
- accessor_: AccessedVia.widget,
- accessLevel: AccessLevel.notAuthed),
- PROFILE('/profile',
- icon: Icons.account_box_rounded,
- label: "Profile",
- accessor_: AccessedVia.drawer,
- accessLevel: AccessLevel.authenticated,
- remoteConfig: true),
- SETTINGS('/settings',
- icon: Icons.settings,
- label: "Settings",
- accessor_: AccessedVia.drawer,
- accessLevel: AccessLevel.authenticated,
- remoteConfig: true),
- CART('/cart',
- icon: Icons.trolley,
- label: "Cart",
- parent: HOME,
- accessor_: AccessedVia.navigator,
- accessLevel: AccessLevel.guest),
- CART_DETAILS('/:productId', parent: CART, accessLevel: AccessLevel.guest),
- CHECKOUT('/checkout',
- icon: Icons.check_outlined,
- label: "Checkout",
- accessor_: AccessedVia.fab, //fab appears in parent
- parent: CART,
- accessLevel: AccessLevel.authenticated),
- REGISTER('/register',
- accessor_: AccessedVia.auto, accessLevel: AccessLevel.authenticated),
- CATEGORIES('/categories',
- icon: Icons.category,
- label: "Categories",
- parent: HOME,
- accessor_: AccessedVia.navigator,
- accessLevel: AccessLevel.roleBased),
- TASKS('/tasks',
- icon: Icons.task,
- label: "Tasks",
- parent: HOME,
- accessor_: AccessedVia.navigator,
- accessLevel: AccessLevel.roleBased),
- TASK_DETAILS('/:taskId', parent: TASKS, accessLevel: AccessLevel.roleBased),
- USERS('/users',
- icon: Icons.verified_user,
- label: "Users",
- parent: HOME,
- accessor_: AccessedVia.navigator,
- accessLevel: AccessLevel.roleBased),
- USER_PROFILE('/:uId', parent: USERS, accessLevel: AccessLevel.roleBased),
- MY_PRODUCTS('/my-products',
- parent: HOME,
- icon: Icons.inventory,
- accessor_: AccessedVia.navigator,
- label: "Inventory",
- accessLevel: AccessLevel.roleBased),
- MY_PRODUCT_DETAILS('/:productId',
- parent: MY_PRODUCTS, accessLevel: AccessLevel.roleBased),
- LOGOUT('/login',
- icon: Icons.logout,
- label: "Logout",
- accessor_: AccessedVia.bottomSheet,
- accessLevel: AccessLevel.authenticated),
- ;
-
- const Screen(this.path,
- {this.icon,
- this.label,
- this.parent,
- this.accessor_ = AccessedVia.singleTap,
- this.accessLevel = AccessLevel.authenticated,
- this.remoteConfig = false});
-
- @override
- final IconData? icon;
- @override
- final String? label;
-
- final String path;
- final AccessedVia accessor_;
- final Screen? parent;
- final AccessLevel
- accessLevel; //if false it is role based. true means allowed for all
- final bool remoteConfig;
-
- Future get accessor async {
- if (remoteConfig &&
- (await RemoteConfig.instance).useBottomSheetForProfileOptions()) {
- return AccessedVia.bottomSheet;
- }
- return accessor_;
- }
-
- Iterable get children =>
- Screen.values.where((Screen screen) => screen.parent == this);
-
- Iterable get fabs => Screen.values.where((Screen screen) =>
- screen.parent == this && screen.accessor_ == AccessedVia.fab);
-
- Iterable get navTabs => Screen.values.where((Screen screen) =>
- screen.parent == this && screen.accessor_ == AccessedVia.navigator);
-
- String get route => (parent != null ? parent?.route : '')! + path;
-
- static Future> sheet(Screen? parent) async {
- List list = [];
- await Future.forEach(Screen.values, (Screen screen) async {
- if (screen.parent == parent &&
- (await screen.accessor) == AccessedVia.bottomSheet) {
- list.add(screen);
- }
- });
- return list;
- }
-
- static Future> drawer() async {
- //drawer is not parent linked
- List list = [];
- await Future.forEach(Screen.values, (Screen screen) async {
- if ((await screen.accessor) == AccessedVia.drawer) {
- list.add(screen);
- }
- });
- return list;
- }
-
- @override
- Future doAction() async {
- if (this == LOGOUT) {
- AuthService.to.logout();
- }
- Get.rootDelegate.toNamed(route);
- }
-
- Widget? widget(GetNavConfig current) =>
- (this == LOGIN) ? LoginBottomSheetToggle(current) : null;
-}
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import '../app/widgets/login_widgets.dart';
+import '../services/remote_config.dart';
+import 'action_enum.dart';
+import 'access_level.dart';
+import '../../services/auth_service.dart';
+
+enum AccessedVia {
+ auto,
+ widget, //example: top right button
+ navigator, //bottom nav. can be linked to drawer items //handled in ScreenWidget
+ drawer, //creates nav tree //handled in RootView
+ bottomSheet, //context menu for web handled via the Button that calls the sheet
+ fab, //handled in ScreenWidget
+ singleTap, //when an item of a list is clicked
+ longTap //or double click
+}
+
+enum Screen implements ActionEnum {
+ HOME('/home',
+ icon: Icons.home,
+ label: "Home",
+ accessor_: AccessedVia.drawer,
+ accessLevel: AccessLevel.public), //first screen is default screen
+ DASHBOARD('/dashboard',
+ icon: Icons.home,
+ label: "Home",
+ accessor_: AccessedVia.navigator,
+ accessLevel: AccessLevel.public,
+ parent: HOME),
+ PRODUCTS('/products',
+ icon: Icons.dataset,
+ label: "Products",
+ accessor_: AccessedVia.navigator,
+ accessLevel: AccessLevel.public,
+ parent: HOME),
+ PRODUCT_DETAILS('/:productId',
+ accessLevel: AccessLevel.public, parent: PRODUCTS),
+ LOGIN('/login',
+ icon: Icons.login,
+ accessor_: AccessedVia.widget,
+ accessLevel: AccessLevel.notAuthed),
+ PROFILE('/profile',
+ icon: Icons.account_box_rounded,
+ label: "Profile",
+ accessor_: AccessedVia.drawer,
+ accessLevel: AccessLevel.authenticated,
+ remoteConfig: true),
+ SETTINGS('/settings',
+ icon: Icons.settings,
+ label: "Settings",
+ accessor_: AccessedVia.drawer,
+ accessLevel: AccessLevel.authenticated,
+ remoteConfig: true),
+ CART('/cart',
+ icon: Icons.trolley,
+ label: "Cart",
+ parent: HOME,
+ accessor_: AccessedVia.navigator,
+ accessLevel: AccessLevel.guest),
+ CART_DETAILS('/:productId', parent: CART, accessLevel: AccessLevel.guest),
+ CHECKOUT('/checkout',
+ icon: Icons.check_outlined,
+ label: "Checkout",
+ accessor_: AccessedVia.fab, //fab appears in parent
+ parent: CART,
+ accessLevel: AccessLevel.authenticated),
+ REGISTER('/register',
+ accessor_: AccessedVia.auto, accessLevel: AccessLevel.authenticated),
+ CATEGORIES('/categories',
+ icon: Icons.category,
+ label: "Categories",
+ parent: HOME,
+ accessor_: AccessedVia.navigator,
+ accessLevel: AccessLevel.roleBased),
+ TASKS('/tasks',
+ icon: Icons.task,
+ label: "Tasks",
+ parent: HOME,
+ accessor_: AccessedVia.navigator,
+ accessLevel: AccessLevel.roleBased),
+ TASK_DETAILS('/:taskId', parent: TASKS, accessLevel: AccessLevel.roleBased),
+ USERS('/users',
+ icon: Icons.verified_user,
+ label: "Users",
+ parent: HOME,
+ accessor_: AccessedVia.navigator,
+ accessLevel: AccessLevel.roleBased),
+ USER_PROFILE('/:uId', parent: USERS, accessLevel: AccessLevel.roleBased),
+ MY_PRODUCTS('/my-products',
+ parent: HOME,
+ icon: Icons.inventory,
+ accessor_: AccessedVia.navigator,
+ label: "Inventory",
+ accessLevel: AccessLevel.roleBased),
+ MY_PRODUCT_DETAILS('/:productId',
+ parent: MY_PRODUCTS, accessLevel: AccessLevel.roleBased),
+ LOGOUT('/login',
+ icon: Icons.logout,
+ label: "Logout",
+ accessor_: AccessedVia.bottomSheet,
+ accessLevel: AccessLevel.authenticated),
+ ;
+
+ const Screen(this.path,
+ {this.icon,
+ this.label,
+ this.parent,
+ this.accessor_ = AccessedVia.singleTap,
+ this.accessLevel = AccessLevel.authenticated,
+ this.remoteConfig = false});
+
+ @override
+ final IconData? icon;
+ @override
+ final String? label;
+
+ final String path;
+ final AccessedVia accessor_;
+ final Screen? parent;
+ final AccessLevel
+ accessLevel; //if false it is role based. true means allowed for all
+ final bool remoteConfig;
+
+ Future get accessor async {
+ if (remoteConfig &&
+ (await RemoteConfig.instance).useBottomSheetForProfileOptions()) {
+ return AccessedVia.bottomSheet;
+ }
+ return accessor_;
+ }
+
+ Iterable get children =>
+ Screen.values.where((Screen screen) => screen.parent == this);
+
+ Iterable get fabs => Screen.values.where((Screen screen) =>
+ screen.parent == this && screen.accessor_ == AccessedVia.fab);
+
+ Iterable get navTabs => Screen.values.where((Screen screen) =>
+ screen.parent == this && screen.accessor_ == AccessedVia.navigator);
+
+ String get route => (parent != null ? parent?.route : '')! + path;
+
+ static Future> sheet(Screen? parent) async {
+ List list = [];
+ await Future.forEach(Screen.values, (Screen screen) async {
+ if (screen.parent == parent &&
+ (await screen.accessor) == AccessedVia.bottomSheet) {
+ list.add(screen);
+ }
+ });
+ return list;
+ }
+
+ static Future> drawer() async {
+ //drawer is not parent linked
+ List list = [];
+ await Future.forEach(Screen.values, (Screen screen) async {
+ if ((await screen.accessor) == AccessedVia.drawer) {
+ list.add(screen);
+ }
+ });
+ return list;
+ }
+
+ @override
+ Future doAction() async {
+ if (this == LOGOUT) {
+ AuthService.to.logout();
+ }
+ Get.rootDelegate.toNamed(route);
+ }
+
+ Widget? widget(GetNavConfig current) =>
+ (this == LOGIN) ? LoginBottomSheetToggle(current) : null;
+}
diff --git a/lib/screen/admin/role_management_screen.dart b/lib/screen/admin/role_management_screen.dart
new file mode 100644
index 00000000..5c087a36
--- /dev/null
+++ b/lib/screen/admin/role_management_screen.dart
@@ -0,0 +1,45 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+// import 'package:your_app/services/role_service.dart';
+
+import '../../services/role_service.dart';
+
+class RoleManagementScreen extends StatelessWidget {
+ final RoleService roleService = Get.find();
+ final uidController = TextEditingController();
+ final roleController = TextEditingController();
+
+ RoleManagementScreen({super.key});
+
+ void assignRole() async {
+ await roleService.setUserRole(uidController.text, roleController.text);
+ Get.snackbar('Success', 'Role assigned successfully!');
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Role Management')),
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ TextField(
+ controller: uidController,
+ decoration: const InputDecoration(labelText: 'User UID'),
+ ),
+ TextField(
+ controller: roleController,
+ decoration: const InputDecoration(labelText: 'Role'),
+ ),
+ const SizedBox(height: 20),
+ ElevatedButton(
+ onPressed: assignRole,
+ child: const Text('Assign Role'),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screen/auth/change_password_screen.dart b/lib/screen/auth/change_password_screen.dart
new file mode 100644
index 00000000..d2b6a48c
--- /dev/null
+++ b/lib/screen/auth/change_password_screen.dart
@@ -0,0 +1,58 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+class ChangePasswordController extends GetxController {
+ var currentPassword = ''.obs;
+ var newPassword = ''.obs;
+ var confirmPassword = ''.obs;
+
+ void changePassword() {
+ // Logic for changing the password goes here.
+ if (newPassword.value == confirmPassword.value) {
+ // Perform password change
+ Get.snackbar('Success', 'Password changed successfully!');
+ } else {
+ Get.snackbar('Error', 'Passwords do not match');
+ }
+ }
+}
+
+class ChangePasswordScreen extends StatelessWidget {
+ final ChangePasswordController controller = Get.put(ChangePasswordController());
+
+ ChangePasswordScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Change Password')),
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ Obx(() => TextField(
+ onChanged: (value) => controller.currentPassword.value = value,
+ decoration: const InputDecoration(labelText: 'Current Password'),
+ obscureText: true,
+ )),
+ Obx(() => TextField(
+ onChanged: (value) => controller.newPassword.value = value,
+ decoration: const InputDecoration(labelText: 'New Password'),
+ obscureText: true,
+ )),
+ Obx(() => TextField(
+ onChanged: (value) => controller.confirmPassword.value = value,
+ decoration: const InputDecoration(labelText: 'Confirm New Password'),
+ obscureText: true,
+ )),
+ const SizedBox(height: 20),
+ ElevatedButton(
+ onPressed: controller.changePassword,
+ child: const Text('Change Password'),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screen/auth/login_screen.dart b/lib/screen/auth/login_screen.dart
new file mode 100644
index 00000000..53318f7f
--- /dev/null
+++ b/lib/screen/auth/login_screen.dart
@@ -0,0 +1,77 @@
+// import 'package:flutter/material.dart';
+// import 'package:get/get.dart';
+// // import 'package:your_app/controllers/recaptcha_controller.dart';
+// //
+// import '../../controllers/recaptcha_controller.dart';
+//
+// class LoginScreen extends StatelessWidget {
+// final ReCaptchaController reCaptchaController = Get.put(ReCaptchaController());
+//
+// const LoginScreen({super.key});
+//
+// @override
+// Widget build(BuildContext context) {
+// return Scaffold(
+// appBar: AppBar(title: const Text('Login')),
+// body: Padding(
+// padding: const EdgeInsets.all(16.0),
+// child: Column(
+// children: [
+// const TextField(
+// decoration: InputDecoration(labelText: 'Email'),
+// ),
+// const TextField(
+// decoration: InputDecoration(labelText: 'Password'),
+// obscureText: true,
+// ),
+// const SizedBox(height: 20),
+// Obx(() => reCaptchaController.isVerified.value
+// ? ElevatedButton(onPressed: () {}, child: const Text('Login'))
+// : ElevatedButton(
+// onPressed: reCaptchaController.verifyRecaptcha,
+// child: const Text('Verify ReCaptcha'),
+// )),
+// ],
+// ),
+// ),
+// );
+// }
+// }
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import '../../controllers/recaptcha_controller.dart';
+
+class LoginScreen extends StatelessWidget {
+ final ReCaptchaController reCaptchaController = Get.put(ReCaptchaController());
+
+ // Remove 'const' from the constructor
+ LoginScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Login')),
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ const TextField(
+ decoration: InputDecoration(labelText: 'Email'),
+ ),
+ const TextField(
+ decoration: InputDecoration(labelText: 'Password'),
+ obscureText: true,
+ ),
+ const SizedBox(height: 20),
+ Obx(() => reCaptchaController.isVerified.value
+ ? ElevatedButton(onPressed: () {}, child: const Text('Login'))
+ : ElevatedButton(
+ onPressed: reCaptchaController.verifyRecaptcha,
+ child: const Text('Verify ReCaptcha'),
+ )),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screen/auth/phone_auth_screen.dart b/lib/screen/auth/phone_auth_screen.dart
new file mode 100644
index 00000000..3efdae63
--- /dev/null
+++ b/lib/screen/auth/phone_auth_screen.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+// import 'package:your_app/controllers/auth_controller.dart';
+
+import '../../controllers/auth_controller.dart';
+
+class PhoneAuthScreen extends StatelessWidget {
+ final AuthController authController = Get.put(AuthController());
+
+ PhoneAuthScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Phone Authentication')),
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ Obx(() => TextField(
+ onChanged: (value) => authController.phoneNumber.value = value,
+ decoration: const InputDecoration(labelText: 'Phone Number'),
+ )),
+ const SizedBox(height: 20),
+ ElevatedButton(
+ onPressed: authController.sendSmsCode,
+ child: const Text('Send SMS Code'),
+ ),
+ Obx(() => TextField(
+ onChanged: (value) => authController.smsCode.value = value,
+ decoration: const InputDecoration(labelText: 'Enter SMS Code'),
+ )),
+ ElevatedButton(
+ onPressed: authController.verifySmsCode,
+ child: const Text('Verify SMS Code'),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screen/auth/reset_password_screen.dart b/lib/screen/auth/reset_password_screen.dart
new file mode 100644
index 00000000..4b0c2ca1
--- /dev/null
+++ b/lib/screen/auth/reset_password_screen.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+// import 'package:your_app/controllers/reset_password_controller.dart';
+
+import '../../controllers/reset_password_controller.dart';
+
+class ResetPasswordScreen extends StatelessWidget {
+ final ResetPasswordController controller = Get.put(ResetPasswordController());
+
+ ResetPasswordScreen({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Reset Password')),
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ Obx(() => TextField(
+ onChanged: (value) => controller.email.value = value,
+ decoration: const InputDecoration(labelText: 'Email'),
+ )),
+ const SizedBox(height: 20),
+ ElevatedButton(
+ onPressed: controller.sendPasswordResetEmail,
+ child: const Text('Send Reset Email'),
+ ),
+ ElevatedButton(
+ onPressed: controller.verifyEmail,
+ child: const Text('Verify Email'),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screen/responsive_layout.dart b/lib/screen/responsive_layout.dart
new file mode 100644
index 00000000..0d193bd7
--- /dev/null
+++ b/lib/screen/responsive_layout.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+
+class ResponsiveLayout extends StatelessWidget {
+ final Widget mobileLayout;
+ final Widget tabletLayout;
+ final Widget desktopLayout;
+
+ const ResponsiveLayout({super.key,
+ required this.mobileLayout,
+ required this.tabletLayout,
+ required this.desktopLayout,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return LayoutBuilder(
+ builder: (context, constraints) {
+ if (constraints.maxWidth < 600) {
+ return mobileLayout;
+ } else if (constraints.maxWidth < 1200) {
+ return tabletLayout;
+ } else {
+ return desktopLayout;
+ }
+ },
+ );
+ }
+}
diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart
index 8bf72aaa..4374ebd7 100644
--- a/lib/services/auth_service.dart
+++ b/lib/services/auth_service.dart
@@ -1,201 +1,201 @@
-// ignore_for_file: avoid_print
-
-import 'package:firebase_auth/firebase_auth.dart';
-import 'package:firebase_ui_auth/firebase_ui_auth.dart' as fbui;
-import 'package:firebase_ui_localizations/firebase_ui_localizations.dart';
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-
-import '../models/screens.dart';
-import '../constants.dart';
-import '../models/role.dart';
-
-class AuthService extends GetxService {
- static AuthService get to => Get.find();
-
- final FirebaseAuth _auth = FirebaseAuth.instance;
- late Rxn credential = Rxn();
- final Rxn _firebaseUser = Rxn();
- final Rx _userRole = Rx(Role.buyer);
- final Rx robot = RxBool(useRecaptcha);
- final RxBool registered = false.obs;
-
- User? get user => _firebaseUser.value;
- Role get maxRole => _userRole.value;
-
- @override
- onInit() {
- super.onInit();
- if (useEmulator) _auth.useAuthEmulator(emulatorHost, 9099);
- _firebaseUser.bindStream(_auth.authStateChanges());
- _auth.authStateChanges().listen((User? user) {
- if (user != null) {
- user.getIdTokenResult().then((token) {
- _userRole.value = Role.fromString(token.claims?["role"]);
- });
- }
- });
- }
-
- bool get isEmailVerified =>
- user != null && (user!.email == null || user!.emailVerified);
-
- bool get isLoggedInValue => user != null;
-
- bool get isAdmin => user != null && _userRole.value == Role.admin;
-
- bool hasRole(Role role) => user != null && _userRole.value == role;
-
- bool get isAnon => user != null && user!.isAnonymous;
-
- String? get userName => (user != null && !user!.isAnonymous)
- ? (user!.displayName ?? user!.email)
- : 'Guest';
-
- void login() {
- // this is not needed as we are using Firebase UI for the login part
- }
-
- void sendVerificationMail({EmailAuthCredential? emailAuth}) async {
- if (sendMailFromClient) {
- if (_auth.currentUser != null) {
- await _auth.currentUser?.sendEmailVerification();
- } else if (emailAuth != null) {
- // Approach 1: sending email auth link requires deep linking which is
- // a TODO as the current Flutter methods are deprecated
- // sendSingInLink(emailAuth);
-
- // Approach 2: This is a hack.
- // We are using createUser to send the verification link from the server side by adding suffix .verify in the email
- // if the user already exists and the password is also same and sign in occurs via custom token on server side
- try {
- await _auth.createUserWithEmailAndPassword(
- email: "${credential.value!.email}.verify",
- password: credential.value!.password!);
- } on FirebaseAuthException catch (e) {
- int i = e.message!.indexOf("message") + 10;
- int j = e.message!.indexOf('"', i);
- Get.snackbar(
- e.message!.substring(i, j),
- 'Please verify your email by clicking the link on the Email sent',
- );
- }
- }
- }
- }
-
- void sendSingInLink(EmailAuthCredential emailAuth) {
- var acs = ActionCodeSettings(
- // URL you want to redirect back to. The domain (www.example.com) for this
- // URL must be whitelisted in the Firebase Console.
- url:
- '$baseUrl:5001/flutterfast-92c25/us-central1/handleEmailLinkVerification',
- // // This must be true if deep linking.
- // // If deeplinking. See [https://firebase.google.com/docs/dynamic-links/flutter/receive]
- handleCodeInApp: true,
- // iOSBundleId: '$bundleID.ios',
- // androidPackageName: '$bundleID.android',
- // // installIfNotAvailable
- // androidInstallApp: true,
- // // minimumVersion
- // androidMinimumVersion: '12'
- );
- _auth
- .sendSignInLinkToEmail(email: emailAuth.email, actionCodeSettings: acs)
- .catchError(
- (onError) => print('Error sending email verification $onError'))
- .then((value) => print('Successfully sent email verification'));
- }
-
- void register() {
- registered.value = true;
- // logout(); // Uncomment if we need to enforce relogin
- final thenTo =
- Get.rootDelegate.currentConfiguration!.currentPage!.parameters?['then'];
- Get.rootDelegate
- .offAndToNamed(thenTo ?? Screen.PROFILE.route); //Profile has the forms
- }
-
- void logout() {
- _auth.signOut();
- if (isAnon) _auth.currentUser?.delete();
- _firebaseUser.value = null;
- }
-
- Future guest() async {
- return await Get.defaultDialog(
- middleText: 'Sign in as Guest',
- barrierDismissible: true,
- onConfirm: loginAsGuest,
- onCancel: () => Get.back(result: false),
- textConfirm: 'Yes, will SignUp later',
- textCancel: 'No, will SignIn now');
- }
-
- void loginAsGuest() async {
- try {
- await FirebaseAuth.instance.signInAnonymously();
- Get.back(result: true);
- Get.snackbar(
- 'Alert!',
- 'Signed in with temporary account.',
- );
- } on FirebaseAuthException catch (e) {
- switch (e.code) {
- case "operation-not-allowed":
- print("Anonymous auth hasn't been enabled for this project.");
- break;
- default:
- print("Unknown error.");
- }
- Get.back(result: false);
- }
- }
-
- void errorMessage(BuildContext context, fbui.AuthFailed state,
- Function(bool, EmailAuthCredential?) callback) {
- fbui.ErrorText.localizeError =
- (BuildContext context, FirebaseAuthException e) {
- final defaultLabels = FirebaseUILocalizations.labelsOf(context);
-
- // for verification error, also set a boolean flag to trigger button visibility to resend verification mail
- String? verification;
- if (e.code == "internal-error" &&
- e.message!.contains('"status":"UNAUTHENTICATED"')) {
- // Note that (possibly in Emulator only) the e.email is always coming as null
- // String? email = e.email ?? parseEmail(e.message!);
- callback(true, credential.value);
- verification =
- "Please verify email id by clicking the link on the email sent";
- } else {
- callback(false, credential.value);
- }
-
- return switch (e.code) {
- 'invalid-credential' => 'User ID or Password incorrect',
- 'user-not-found' => 'Please create an account first.',
- 'credential-already-in-use' => 'This email is already in use.',
- _ => fbui.localizedErrorText(e.code, defaultLabels) ??
- verification ??
- 'Oh no! Something went wrong.',
- };
- };
- }
-}
-
-class MyCredential extends AuthCredential {
- final EmailAuthCredential cred;
- MyCredential(this.cred)
- : super(providerId: "custom", signInMethod: cred.signInMethod);
-
- @override
- Map asMap() {
- return cred.asMap();
- }
-}
-
-parseEmail(String message) {
- int i = message.indexOf('"message":') + 13;
- int j = message.indexOf('"', i);
- return message.substring(i, j - 1);
-}
+// ignore_for_file: avoid_print
+
+import 'package:firebase_auth/firebase_auth.dart';
+import 'package:firebase_ui_auth/firebase_ui_auth.dart' as fbui;
+import 'package:firebase_ui_localizations/firebase_ui_localizations.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../models/screens.dart';
+import '../constants.dart';
+import '../models/role.dart';
+
+class AuthService extends GetxService {
+ static AuthService get to => Get.find();
+
+ final FirebaseAuth _auth = FirebaseAuth.instance;
+ late Rxn credential = Rxn();
+ final Rxn _firebaseUser = Rxn();
+ final Rx _userRole = Rx(Role.buyer);
+ final Rx robot = RxBool(useRecaptcha);
+ final RxBool registered = false.obs;
+
+ User? get user => _firebaseUser.value;
+ Role get maxRole => _userRole.value;
+
+ @override
+ onInit() {
+ super.onInit();
+ if (useEmulator) _auth.useAuthEmulator(emulatorHost, 9099);
+ _firebaseUser.bindStream(_auth.authStateChanges());
+ _auth.authStateChanges().listen((User? user) {
+ if (user != null) {
+ user.getIdTokenResult().then((token) {
+ _userRole.value = Role.fromString(token.claims?["role"]);
+ });
+ }
+ });
+ }
+
+ bool get isEmailVerified =>
+ user != null && (user!.email == null || user!.emailVerified);
+
+ bool get isLoggedInValue => user != null;
+
+ bool get isAdmin => user != null && _userRole.value == Role.admin;
+
+ bool hasRole(Role role) => user != null && _userRole.value == role;
+
+ bool get isAnon => user != null && user!.isAnonymous;
+
+ String? get userName => (user != null && !user!.isAnonymous)
+ ? (user!.displayName ?? user!.email)
+ : 'Guest';
+
+ void login() {
+ // this is not needed as we are using Firebase UI for the login part
+ }
+
+ void sendVerificationMail({EmailAuthCredential? emailAuth}) async {
+ if (sendMailFromClient) {
+ if (_auth.currentUser != null) {
+ await _auth.currentUser?.sendEmailVerification();
+ } else if (emailAuth != null) {
+ // Approach 1: sending email auth link requires deep linking which is
+ // a TODO as the current Flutter methods are deprecated
+ // sendSingInLink(emailAuth);
+
+ // Approach 2: This is a hack.
+ // We are using createUser to send the verification link from the server side by adding suffix .verify in the email
+ // if the user already exists and the password is also same and sign in occurs via custom token on server side
+ try {
+ await _auth.createUserWithEmailAndPassword(
+ email: "${credential.value!.email}.verify",
+ password: credential.value!.password!);
+ } on FirebaseAuthException catch (e) {
+ int i = e.message!.indexOf("message") + 10;
+ int j = e.message!.indexOf('"', i);
+ Get.snackbar(
+ e.message!.substring(i, j),
+ 'Please verify your email by clicking the link on the Email sent',
+ );
+ }
+ }
+ }
+ }
+
+ void sendSingInLink(EmailAuthCredential emailAuth) {
+ var acs = ActionCodeSettings(
+ // URL you want to redirect back to. The domain (www.example.com) for this
+ // URL must be whitelisted in the Firebase Console.
+ url:
+ '$baseUrl:5001/flutterfast-92c25/us-central1/handleEmailLinkVerification',
+ // // This must be true if deep linking.
+ // // If deeplinking. See [https://firebase.google.com/docs/dynamic-links/flutter/receive]
+ handleCodeInApp: true,
+ // iOSBundleId: '$bundleID.ios',
+ // androidPackageName: '$bundleID.android',
+ // // installIfNotAvailable
+ // androidInstallApp: true,
+ // // minimumVersion
+ // androidMinimumVersion: '12'
+ );
+ _auth
+ .sendSignInLinkToEmail(email: emailAuth.email, actionCodeSettings: acs)
+ .catchError(
+ (onError) => print('Error sending email verification $onError'))
+ .then((value) => print('Successfully sent email verification'));
+ }
+
+ void register() {
+ registered.value = true;
+ // logout(); // Uncomment if we need to enforce relogin
+ final thenTo =
+ Get.rootDelegate.currentConfiguration!.currentPage!.parameters?['then'];
+ Get.rootDelegate
+ .offAndToNamed(thenTo ?? Screen.PROFILE.route); //Profile has the forms
+ }
+
+ void logout() {
+ _auth.signOut();
+ if (isAnon) _auth.currentUser?.delete();
+ _firebaseUser.value = null;
+ }
+
+ Future guest() async {
+ return await Get.defaultDialog(
+ middleText: 'Sign in as Guest',
+ barrierDismissible: true,
+ onConfirm: loginAsGuest,
+ onCancel: () => Get.back(result: false),
+ textConfirm: 'Yes, will SignUp later',
+ textCancel: 'No, will SignIn now');
+ }
+
+ void loginAsGuest() async {
+ try {
+ await FirebaseAuth.instance.signInAnonymously();
+ Get.back(result: true);
+ Get.snackbar(
+ 'Alert!',
+ 'Signed in with temporary account.',
+ );
+ } on FirebaseAuthException catch (e) {
+ switch (e.code) {
+ case "operation-not-allowed":
+ print("Anonymous auth hasn't been enabled for this project.");
+ break;
+ default:
+ print("Unknown error.");
+ }
+ Get.back(result: false);
+ }
+ }
+
+ void errorMessage(BuildContext context, fbui.AuthFailed state,
+ Function(bool, EmailAuthCredential?) callback) {
+ fbui.ErrorText.localizeError =
+ (BuildContext context, FirebaseAuthException e) {
+ final defaultLabels = FirebaseUILocalizations.labelsOf(context);
+
+ // for verification error, also set a boolean flag to trigger button visibility to resend verification mail
+ String? verification;
+ if (e.code == "internal-error" &&
+ e.message!.contains('"status":"UNAUTHENTICATED"')) {
+ // Note that (possibly in Emulator only) the e.email is always coming as null
+ // String? email = e.email ?? parseEmail(e.message!);
+ callback(true, credential.value);
+ verification =
+ "Please verify email id by clicking the link on the email sent";
+ } else {
+ callback(false, credential.value);
+ }
+
+ return switch (e.code) {
+ 'invalid-credential' => 'User ID or Password incorrect',
+ 'user-not-found' => 'Please create an account first.',
+ 'credential-already-in-use' => 'This email is already in use.',
+ _ => fbui.localizedErrorText(e.code, defaultLabels) ??
+ verification ??
+ 'Oh no! Something went wrong.',
+ };
+ };
+ }
+}
+
+class MyCredential extends AuthCredential {
+ final EmailAuthCredential cred;
+ MyCredential(this.cred)
+ : super(providerId: "custom", signInMethod: cred.signInMethod);
+
+ @override
+ Map asMap() {
+ return cred.asMap();
+ }
+}
+
+parseEmail(String message) {
+ int i = message.indexOf('"message":') + 13;
+ int j = message.indexOf('"', i);
+ return message.substring(i, j - 1);
+}
diff --git a/lib/services/remote_config.dart b/lib/services/remote_config.dart
index 5d1145a5..416943bc 100644
--- a/lib/services/remote_config.dart
+++ b/lib/services/remote_config.dart
@@ -1,78 +1,78 @@
-import 'package:firebase_remote_config/firebase_remote_config.dart';
-import 'package:get/get_utils/src/platform/platform.dart';
-
-enum Typer { integer, boolean, double, string }
-
-class RemoteConfig {
- static RemoteConfig? _instance;
-
- static Future get instance async {
- _instance = _instance ?? RemoteConfig();
- await _instance!.init();
- return _instance!;
- }
-
- final FirebaseRemoteConfig _remoteConfig = FirebaseRemoteConfig.instance;
- final List listeners = [];
-
- Future init() async {
- await _remoteConfig.setConfigSettings(RemoteConfigSettings(
- fetchTimeout: const Duration(minutes: 1),
- minimumFetchInterval: //const Duration(hours: 1), //use for prod
- const Duration(minutes: 5), //use for testing only
- ));
-
- await _remoteConfig.setDefaults(const {
- "useBottomSheetForProfileOptions": false,
- "showSearchBarOnTop": true,
- });
-
- await fetch();
- }
-
- Future fetch() async {
- return await _remoteConfig.fetchAndActivate();
- }
-
-//can be used to change config without restart
- void addListener(String key, Typer typ, Function listener) async {
- if (!GetPlatform.isWeb) {
- _remoteConfig.onConfigUpdated. //not supported in web
- listen((event) async {
- await _remoteConfig.activate();
- if (event.updatedKeys.contains(key)) {
- _remoteConfig.fetch();
- var val = _remoteConfig.getValue(key);
- switch (typ) {
- case Typer.integer:
- listener(val.asInt());
- break;
- case Typer.boolean:
- listener(val.asInt());
- break;
- case Typer.double:
- listener(val.asDouble());
- break;
- default:
- listener(val.asString());
- }
- }
- });
- }
- }
-
- bool useBottomSheetForProfileOptions() {
- return _remoteConfig.getBool("useBottomSheetForProfileOptions");
- }
-
- bool showSearchBarOnTop() {
- return _remoteConfig.getBool("showSearchBarOnTop");
- }
-
- void addUseBottomSheetForProfileOptionsListener(listener) {
- addListener("useBottomSheetForProfileOptions", Typer.boolean, listener);
- if (!listeners.contains(listener)) {
- listeners.add(listener);
- }
- }
-}
+import 'package:firebase_remote_config/firebase_remote_config.dart';
+import 'package:get/get_utils/src/platform/platform.dart';
+
+enum Typer { integer, boolean, double, string }
+
+class RemoteConfig {
+ static RemoteConfig? _instance;
+
+ static Future