From 379ac72766b8429f01ebca7b976378f9e052c2f7 Mon Sep 17 00:00:00 2001 From: Hardik Date: Thu, 11 Jul 2024 03:05:19 +0530 Subject: [PATCH 01/23] refactor: organize asset constants --- lib/app/modules/profile/views/profile_view.dart | 3 ++- lib/app/modules/root/views/root_view.dart | 3 ++- lib/app/utils/icon_constants.dart | 5 +++++ lib/app/utils/img_constants.dart | 6 ++++++ lib/app/widgets/login_widgets.dart | 5 +++-- pubspec.yaml | 6 +++--- 6 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 lib/app/utils/icon_constants.dart create mode 100644 lib/app/utils/img_constants.dart diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index c26d11c1..cd9b8e28 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import '../../../../services/auth_service.dart'; import '../../../../models/screens.dart'; +import '../../../utils/img_constants.dart'; import '../../../widgets/change_password_dialog.dart'; import '../../../widgets/image_picker_button.dart'; import '../controllers/profile_controller.dart'; @@ -62,7 +63,7 @@ class ProfileView extends GetView { ) : Center( child: Image.asset( - 'assets/images/dash.png', + ImgConstants.dash, width: size, fit: BoxFit.contain, ), diff --git a/lib/app/modules/root/views/root_view.dart b/lib/app/modules/root/views/root_view.dart index 2bbf228c..e5be177b 100644 --- a/lib/app/modules/root/views/root_view.dart +++ b/lib/app/modules/root/views/root_view.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:get_flutter_fire/services/auth_service.dart'; import '../../../routes/app_pages.dart'; import '../../../../models/screens.dart'; +import '../../../utils/icon_constants.dart'; import '../controllers/root_controller.dart'; import 'drawer.dart'; @@ -31,7 +32,7 @@ class RootView extends GetView { ) : IconButton( icon: ImageIcon( - const AssetImage("icons/logo.png"), + const AssetImage(IconConstants.logo), color: Colors.grey.shade800, ), onPressed: () => AuthService.to.isLoggedInValue diff --git a/lib/app/utils/icon_constants.dart b/lib/app/utils/icon_constants.dart new file mode 100644 index 00000000..b3351a95 --- /dev/null +++ b/lib/app/utils/icon_constants.dart @@ -0,0 +1,5 @@ +abstract class IconConstants { + static const _assetsIcon = 'assets/icons'; + + static const logo = '$_assetsIcon/logo.png'; +} diff --git a/lib/app/utils/img_constants.dart b/lib/app/utils/img_constants.dart new file mode 100644 index 00000000..a2be2f73 --- /dev/null +++ b/lib/app/utils/img_constants.dart @@ -0,0 +1,6 @@ +abstract class ImgConstants { + static const _assetsImg = 'assets/image'; + + static const dash = '$_assetsImg/dash.png'; + static const flutterfire = '$_assetsImg/flutterfire_300x.png'; +} diff --git a/lib/app/widgets/login_widgets.dart b/lib/app/widgets/login_widgets.dart index b8f2d8c1..98d6f950 100644 --- a/lib/app/widgets/login_widgets.dart +++ b/lib/app/widgets/login_widgets.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import '../../services/auth_service.dart'; import '../../models/screens.dart'; import '../../services/remote_config.dart'; +import '../utils/img_constants.dart'; import 'menu_sheet_button.dart'; class LoginWidgets { @@ -14,7 +15,7 @@ class LoginWidgets { padding: const EdgeInsets.all(20), child: AspectRatio( aspectRatio: 1, - child: Image.asset('assets/images/flutterfire_300x.png'), + child: Image.asset(ImgConstants.flutterfire), ), ); } @@ -38,7 +39,7 @@ class LoginWidgets { padding: const EdgeInsets.all(20), child: AspectRatio( aspectRatio: 1, - child: Image.asset('assets/images/flutterfire_300x.png'), + child: Image.asset(ImgConstants.flutterfire), ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 2909a374..d000e5f5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,8 +36,8 @@ flutter: fonts: - asset: packages/firebase_ui_auth/fonts/SocialIcons.ttf assets: - - assets/images/flutterfire_300x.png - - assets/images/dash.png - - assets/icons/logo.png + - assets/ + - assets/images/ + - assets/icons/ uses-material-design: true From 255019f945da70574f0ecfbd0252891105c69080 Mon Sep 17 00:00:00 2001 From: Hardik Date: Thu, 11 Jul 2024 03:13:10 +0530 Subject: [PATCH 02/23] fix: correct path typo from 'assets/image' to 'assets/images' --- lib/app/utils/img_constants.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/app/utils/img_constants.dart b/lib/app/utils/img_constants.dart index a2be2f73..83a5c0c6 100644 --- a/lib/app/utils/img_constants.dart +++ b/lib/app/utils/img_constants.dart @@ -1,5 +1,5 @@ abstract class ImgConstants { - static const _assetsImg = 'assets/image'; + static const _assetsImg = 'assets/images'; static const dash = '$_assetsImg/dash.png'; static const flutterfire = '$_assetsImg/flutterfire_300x.png'; From fed66e8bc8349512fe44d15ca028246c73281a7b Mon Sep 17 00:00:00 2001 From: neminsheth Date: Fri, 12 Jul 2024 15:11:12 +0530 Subject: [PATCH 03/23] Add Firebase configuration and setup Android/iOS platforms --- .metadata | 25 +- android/app/google-services.json | 82 +++++ .../example/get_flutter_fire/MainActivity.kt | 5 + firebase.json | 1 + ios/Podfile | 44 +++ ios/Podfile.lock | 346 ++++++++++++++++++ ios/Runner/GoogleService-Info.plist | 34 ++ macos/Podfile | 43 +++ macos/Runner/GoogleService-Info.plist | 34 ++ pubspec.lock | 88 ++--- 10 files changed, 653 insertions(+), 49 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt create mode 100644 firebase.json create mode 100644 ios/Podfile create mode 100644 ios/Podfile.lock create mode 100644 ios/Runner/GoogleService-Info.plist create mode 100644 macos/Podfile create mode 100644 macos/Runner/GoogleService-Info.plist diff --git a/.metadata b/.metadata index 784ce129..6eb54a17 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" + revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" channel: "stable" project_type: app @@ -13,11 +13,26 @@ project_type: app migration: platforms: - platform: root - create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 - base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: android + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: ios + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: linux + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: macos + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - platform: web - create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 - base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: windows + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 # User provided section diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..41ea6bf4 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,82 @@ +{ + "project_info": { + "project_number": "56053565487", + "project_id": "sharekhan-nemin", + "storage_bucket": "sharekhan-nemin.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:56053565487:android:f0e57a6359c84f97cb5eda", + "android_client_info": { + "package_name": "nemin.sharekhan" + } + }, + "oauth_client": [ + { + "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyA42S1sFkyQAj1yZ1F4gUmE_pxec3h3YBw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.example.getFlutterFire" + } + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:56053565487:android:a10bbf5abca35d98cb5eda", + "android_client_info": { + "package_name": "sharekhan.nemin" + } + }, + "oauth_client": [ + { + "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyA42S1sFkyQAj1yZ1F4gUmE_pxec3h3YBw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.example.getFlutterFire" + } + } + ] + } + } + } + ], + "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..018e286b --- /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/firebase.json b/firebase.json new file mode 100644 index 00000000..6643fe7b --- /dev/null +++ b/firebase.json @@ -0,0 +1 @@ +{"flutter":{"platforms":{"dart":{"lib/firebase_options.dart":{"projectId":"sharekhan-nemin","configurations":{"android":"1:56053565487:android:f0e57a6359c84f97cb5eda","ios":"1:56053565487:ios:3515d315addadb07cb5eda","macos":"1:56053565487:ios:3515d315addadb07cb5eda","web":"1:56053565487:web:bdde9b35d35b497ccb5eda","windows":"1:56053565487:web:5c35ec65002974a6cb5eda"}}},"ios":{"default":{"projectId":"sharekhan-nemin","appId":"1:56053565487:ios:3515d315addadb07cb5eda","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"android":{"default":{"projectId":"sharekhan-nemin","appId":"1:56053565487:android:f0e57a6359c84f97cb5eda","fileOutput":"android/app/google-services.json"}},"macos":{"default":{"projectId":"sharekhan-nemin","appId":"1:56053565487:ios:3515d315addadb07cb5eda","uploadDebugSymbols":false,"fileOutput":"macos/Runner/GoogleService-Info.plist"}}}}} \ No newline at end of file diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 00000000..d97f17e2 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 00000000..6afd14af --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,346 @@ +PODS: + - AppAuth (1.7.5): + - AppAuth/Core (= 1.7.5) + - AppAuth/ExternalUserAgent (= 1.7.5) + - AppAuth/Core (1.7.5) + - AppAuth/ExternalUserAgent (1.7.5): + - AppAuth/Core + - desktop_webview_auth (0.0.1): + - Flutter + - DKImagePickerController/Core (4.3.9): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.9) + - DKImagePickerController/PhotoGallery (4.3.9): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.9) + - DKPhotoGallery (0.0.19): + - DKPhotoGallery/Core (= 0.0.19) + - DKPhotoGallery/Model (= 0.0.19) + - DKPhotoGallery/Preview (= 0.0.19) + - DKPhotoGallery/Resource (= 0.0.19) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.19): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.19): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - Firebase/Analytics (10.25.0): + - Firebase/Core + - Firebase/Auth (10.25.0): + - Firebase/CoreOnly + - FirebaseAuth (~> 10.25.0) + - Firebase/Core (10.25.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 10.25.0) + - Firebase/CoreOnly (10.25.0): + - FirebaseCore (= 10.25.0) + - Firebase/DynamicLinks (10.25.0): + - Firebase/CoreOnly + - FirebaseDynamicLinks (~> 10.25.0) + - Firebase/RemoteConfig (10.25.0): + - Firebase/CoreOnly + - FirebaseRemoteConfig (~> 10.25.0) + - Firebase/Storage (10.25.0): + - Firebase/CoreOnly + - FirebaseStorage (~> 10.25.0) + - firebase_analytics (10.10.7): + - Firebase/Analytics (= 10.25.0) + - firebase_core + - Flutter + - firebase_auth (4.20.0): + - Firebase/Auth (= 10.25.0) + - firebase_core + - Flutter + - firebase_core (2.32.0): + - Firebase/CoreOnly (= 10.25.0) + - Flutter + - firebase_dynamic_links (5.5.7): + - Firebase/DynamicLinks (= 10.25.0) + - firebase_core + - Flutter + - firebase_remote_config (4.4.7): + - Firebase/RemoteConfig (= 10.25.0) + - firebase_core + - Flutter + - firebase_storage (11.7.7): + - Firebase/Storage (= 10.25.0) + - firebase_core + - Flutter + - FirebaseABTesting (10.29.0): + - FirebaseCore (~> 10.0) + - FirebaseAnalytics (10.25.0): + - FirebaseAnalytics/AdIdSupport (= 10.25.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30911.0, >= 2.30908.0) + - FirebaseAnalytics/AdIdSupport (10.25.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleAppMeasurement (= 10.25.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30911.0, >= 2.30908.0) + - FirebaseAppCheckInterop (10.29.0) + - FirebaseAuth (10.25.0): + - FirebaseAppCheckInterop (~> 10.17) + - FirebaseCore (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/Environment (~> 7.8) + - GTMSessionFetcher/Core (< 4.0, >= 2.1) + - RecaptchaInterop (~> 100.0) + - FirebaseAuthInterop (10.29.0) + - FirebaseCore (10.25.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.12) + - GoogleUtilities/Logger (~> 7.12) + - FirebaseCoreExtension (10.29.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreInternal (10.29.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseDynamicLinks (10.25.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (10.29.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - FirebaseRemoteConfig (10.25.0): + - FirebaseABTesting (~> 10.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - FirebaseRemoteConfigInterop (~> 10.23) + - FirebaseSharedSwift (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseRemoteConfigInterop (10.29.0) + - FirebaseSharedSwift (10.29.0) + - FirebaseStorage (10.25.0): + - FirebaseAppCheckInterop (~> 10.0) + - FirebaseAuthInterop (~> 10.25) + - FirebaseCore (~> 10.0) + - FirebaseCoreExtension (~> 10.0) + - GoogleUtilities/Environment (~> 7.12) + - GTMSessionFetcher/Core (< 4.0, >= 2.1) + - Flutter (1.0.0) + - google_sign_in_ios (0.0.1): + - AppAuth (>= 1.7.4) + - Flutter + - FlutterMacOS + - GoogleSignIn (~> 7.1) + - GTMSessionFetcher (>= 3.4.0) + - GoogleAppMeasurement (10.25.0): + - GoogleAppMeasurement/AdIdSupport (= 10.25.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30911.0, >= 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (10.25.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.25.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30911.0, >= 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (10.25.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" + - nanopb (< 2.30911.0, >= 2.30908.0) + - GoogleSignIn (7.1.0): + - AppAuth (< 2.0, >= 1.7.3) + - GTMAppAuth (< 5.0, >= 4.1.1) + - GTMSessionFetcher/Core (~> 3.3) + - GoogleUtilities/AppDelegateSwizzler (7.13.3): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (7.13.3): + - GoogleUtilities/Privacy + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.13.3): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - GoogleUtilities/MethodSwizzler (7.13.3): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilities/Network (7.13.3): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.13.3)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (7.13.3) + - GoogleUtilities/Reachability (7.13.3): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilities/UserDefaults (7.13.3): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GTMAppAuth (4.1.1): + - AppAuth/Core (~> 1.7) + - GTMSessionFetcher/Core (< 4.0, >= 3.3) + - GTMSessionFetcher (3.5.0): + - GTMSessionFetcher/Full (= 3.5.0) + - GTMSessionFetcher/Core (3.5.0) + - GTMSessionFetcher/Full (3.5.0): + - GTMSessionFetcher/Core + - image_picker_ios (0.0.1): + - Flutter + - nanopb (2.30910.0): + - nanopb/decode (= 2.30910.0) + - nanopb/encode (= 2.30910.0) + - nanopb/decode (2.30910.0) + - nanopb/encode (2.30910.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - PromisesObjC (2.4.0) + - RecaptchaInterop (100.0.0) + - SDWebImage (5.19.4): + - SDWebImage/Core (= 5.19.4) + - SDWebImage/Core (5.19.4) + - SwiftyGif (5.4.5) + +DEPENDENCIES: + - desktop_webview_auth (from `.symlinks/plugins/desktop_webview_auth/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) + - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_dynamic_links (from `.symlinks/plugins/firebase_dynamic_links/ios`) + - firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`) + - firebase_storage (from `.symlinks/plugins/firebase_storage/ios`) + - Flutter (from `Flutter`) + - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + +SPEC REPOS: + trunk: + - AppAuth + - DKImagePickerController + - DKPhotoGallery + - Firebase + - FirebaseABTesting + - FirebaseAnalytics + - FirebaseAppCheckInterop + - FirebaseAuth + - FirebaseAuthInterop + - FirebaseCore + - FirebaseCoreExtension + - FirebaseCoreInternal + - FirebaseDynamicLinks + - FirebaseInstallations + - FirebaseRemoteConfig + - FirebaseRemoteConfigInterop + - FirebaseSharedSwift + - FirebaseStorage + - GoogleAppMeasurement + - GoogleSignIn + - GoogleUtilities + - GTMAppAuth + - GTMSessionFetcher + - nanopb + - PromisesObjC + - RecaptchaInterop + - SDWebImage + - SwiftyGif + +EXTERNAL SOURCES: + desktop_webview_auth: + :path: ".symlinks/plugins/desktop_webview_auth/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + firebase_analytics: + :path: ".symlinks/plugins/firebase_analytics/ios" + firebase_auth: + :path: ".symlinks/plugins/firebase_auth/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_dynamic_links: + :path: ".symlinks/plugins/firebase_dynamic_links/ios" + firebase_remote_config: + :path: ".symlinks/plugins/firebase_remote_config/ios" + firebase_storage: + :path: ".symlinks/plugins/firebase_storage/ios" + Flutter: + :path: Flutter + google_sign_in_ios: + :path: ".symlinks/plugins/google_sign_in_ios/darwin" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + +SPEC CHECKSUMS: + AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa + desktop_webview_auth: d645139460ef203d50bd0cdb33356785dd939cce + DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c + DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 + file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + Firebase: 0312a2352584f782ea56f66d91606891d4607f06 + firebase_analytics: cc06e24d6a2343c44f845b3112143db72d10ef78 + firebase_auth: 5719ddc9f654b813405899480e84971bd8e61235 + firebase_core: a626d00494efa398e7c54f25f1454a64c8abf197 + firebase_dynamic_links: 525e9c1b702d2ed2d9b0dbd342eee1e15a75e62d + firebase_remote_config: 7b05c80210ab558c80f7a756681022b4ee98eea0 + firebase_storage: 5c0f552d6b27d621429d7fd16ebab4be94a3c954 + FirebaseABTesting: d87f56707159bae64e269757a6e963d490f2eebe + FirebaseAnalytics: ec00fe8b93b41dc6fe4a28784b8e51da0647a248 + FirebaseAppCheckInterop: 6a1757cfd4067d8e00fccd14fcc1b8fd78cfac07 + FirebaseAuth: c0f93dcc570c9da2bffb576969d793e95c344fbb + FirebaseAuthInterop: 17db81e9b198afb0f95ce48c133825727eed55d3 + FirebaseCore: 7ec4d0484817f12c3373955bc87762d96842d483 + FirebaseCoreExtension: 705ca5b14bf71d2564a0ddc677df1fc86ffa600f + FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934 + FirebaseDynamicLinks: 12c9f5b643943e0565ed28080373f89cbcb914a3 + FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd + FirebaseRemoteConfig: 9f3935cefecd85d5b312192117f444957de24a75 + FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d + FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e + FirebaseStorage: 44f4e25073f6fa0d4d8c09f5bec299ee9e4eb985 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + google_sign_in_ios: 07375bfbf2620bc93a602c0e27160d6afc6ead38 + GoogleAppMeasurement: 9abf64b682732fed36da827aa2a68f0221fd2356 + GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db + GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 + GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de + GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 + image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 + nanopb: 438bc412db1928dac798aa6fd75726007be04262 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21 + SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.14.2 diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..78e3a245 --- /dev/null +++ b/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo + API_KEY + AIzaSyD12e9qHOj8ulb6cxP0DIWHW2tIeYzgKtc + GCM_SENDER_ID + 56053565487 + PLIST_VERSION + 1 + BUNDLE_ID + com.example.getFlutterFire + PROJECT_ID + sharekhan-nemin + STORAGE_BUCKET + sharekhan-nemin.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:56053565487:ios:3515d315addadb07cb5eda + + \ No newline at end of file diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 00000000..c795730d --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Runner/GoogleService-Info.plist b/macos/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..78e3a245 --- /dev/null +++ b/macos/Runner/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo + API_KEY + AIzaSyD12e9qHOj8ulb6cxP0DIWHW2tIeYzgKtc + GCM_SENDER_ID + 56053565487 + PLIST_VERSION + 1 + BUNDLE_ID + com.example.getFlutterFire + PROJECT_ID + sharekhan-nemin + STORAGE_BUCKET + sharekhan-nemin.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:56053565487:ios:3515d315addadb07cb5eda + + \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 877fc75e..d0fdd9cb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -117,10 +117,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" + sha256: "824f5b9f389bfc4dddac3dea76cd70c51092d9dff0b2ece7ef4f53db8547d258" url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.0.6" file_selector_linux: dependency: transitive description: @@ -181,26 +181,26 @@ packages: dependency: "direct main" description: name: firebase_auth - sha256: f0a75f61992d036e4c46ad0e9febd364d98aa2c092690a5475cb1421a8243cfe + sha256: cfc2d970829202eca09e2896f0a5aa7c87302817ecc0bdfa954f026046bf10ba url: "https://pub.dev" source: hosted - version: "4.19.5" + version: "4.20.0" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: feb77258404309ffc7761c78e1c0ad2ed5e4fdc378e035619e2cc13be4397b62 + sha256: a0270e1db3b2098a14cb2a2342b3cd2e7e458e0c391b1f64f6f78b14296ec093 url: "https://pub.dev" source: hosted - version: "7.2.6" + version: "7.3.0" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: "6d527f357da2bf93a67a42b423aa92943104a0c290d1d72ad9a42c779d501cd2" + sha256: "64e067e763c6378b7e774e872f0f59f6812885e43020e25cde08f42e9459837b" url: "https://pub.dev" source: hosted - version: "5.11.5" + version: "5.12.0" firebase_core: dependency: "direct main" description: @@ -213,34 +213,34 @@ packages: dependency: transitive description: name: firebase_core_platform_interface - sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63 + sha256: "1003a5a03a61fc9a22ef49f37cbcb9e46c86313a7b2e7029b9390cf8c6fc32cb" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.1.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "43d9e951ac52b87ae9cc38ecdcca1e8fa7b52a1dd26a96085ba41ce5108db8e9" + sha256: "23509cb3cddfb3c910c143279ac3f07f06d3120f7d835e4a5d4b42558e978712" url: "https://pub.dev" source: hosted - version: "2.17.0" + version: "2.17.3" firebase_dynamic_links: dependency: transitive description: name: firebase_dynamic_links - sha256: f704859abc17d99e74b47eaf47455b45a88ab7e2973f03e6130ff666b45fe11f + sha256: "47b8c8a8546d8a7f9000edb90848549f20b137d814ee7e0407b3d43b8445e282" url: "https://pub.dev" source: hosted - version: "5.5.5" + version: "5.5.7" firebase_dynamic_links_platform_interface: dependency: transitive description: name: firebase_dynamic_links_platform_interface - sha256: f86992605b50e2f0ce6c24993430affc98021da8d8a74d5596b7a2c84196c110 + sha256: "72e7810635f908ce060c5803c7acb29116c5b6befc73e90446c52722bc9506a2" url: "https://pub.dev" source: hosted - version: "0.2.6+33" + version: "0.2.6+35" firebase_remote_config: dependency: "direct main" description: @@ -269,26 +269,26 @@ packages: dependency: "direct main" description: name: firebase_storage - sha256: da76ca9c11d795c4bae1bd13b31d54bb9eb9ccbee7eb5f6b86b8294370e9d488 + sha256: "2ae478ceec9f458c1bcbf0ee3e0100e4e909708979e83f16d5d9fba35a5b42c1" url: "https://pub.dev" source: hosted - version: "11.7.5" + version: "11.7.7" firebase_storage_platform_interface: dependency: transitive description: name: firebase_storage_platform_interface - sha256: be17bfa9110a6429b40dd3760c755034079fd734aa1dd2476d5638ab780cc508 + sha256: "4e18662e6a66e2e0e181c06f94707de06d5097d70cfe2b5141bf64660c5b5da9" url: "https://pub.dev" source: hosted - version: "5.1.20" + version: "5.1.22" firebase_storage_web: dependency: transitive description: name: firebase_storage_web - sha256: "5219c20c0768a8e2ffedf0a116b7bc80ab32fcc6e2cbd50cbde14f8c4575c3f4" + sha256: "3a44aacd38a372efb159f6fe36bb4a7d79823949383816457fd43d3d47602a53" url: "https://pub.dev" source: hosted - version: "3.9.5" + version: "3.9.7" firebase_ui_auth: dependency: "direct main" description: @@ -351,10 +351,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" + sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e url: "https://pub.dev" source: hosted - version: "2.0.19" + version: "2.0.20" flutter_svg: dependency: transitive description: @@ -417,10 +417,10 @@ packages: dependency: transitive description: name: google_sign_in_android - sha256: "7647893c65e6720973f0e579051c8f84b877b486614d9f70a404259c41a4632e" + sha256: d30fb34b659679ea74397e9748b4ab5d720720d57dcc79538f1b3c4a68654cb3 url: "https://pub.dev" source: hosted - version: "6.1.23" + version: "6.1.27" google_sign_in_ios: dependency: transitive description: @@ -441,10 +441,10 @@ packages: dependency: transitive description: name: google_sign_in_web - sha256: fc0f14ed45ea616a6cfb4d1c7534c2221b7092cc4f29a709f0c3053cc3e821bd + sha256: d606264c7a1a526a3aa79d938b85a601d8589731a478bd4a3dcbdeb14a572228 url: "https://pub.dev" source: hosted - version: "0.12.4" + version: "0.12.4+1" http: dependency: transitive description: @@ -465,18 +465,18 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "79455f6cff4cbef583b2b524bbf0d4ec424e5959f4d464e36ef5323715b98370" + sha256: ff39a10ab4f48f4ac70776d0494a97bf073cd2570892cd46bc8a5cac162c25db url: "https://pub.dev" source: hosted - version: "0.8.12" + version: "0.8.12+4" image_picker_for_web: dependency: transitive description: @@ -489,10 +489,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: cb0db0ec0d3e2cd49674f2e6053be25ccdb959832607c1cbd215dd6cf10fb0dd + sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447" url: "https://pub.dev" source: hosted - version: "0.8.11" + version: "0.8.12" image_picker_linux: dependency: transitive description: @@ -625,10 +625,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.7" path_provider_foundation: dependency: transitive description: @@ -657,10 +657,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -673,10 +673,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -798,10 +798,10 @@ packages: dependency: transitive description: name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" + sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.5.1" xdg_directories: dependency: transitive description: @@ -819,5 +819,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.3.4 <4.0.0" - flutter: ">=3.19.2" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" From c11c7942b2b5d736e96067db3c571dc789de75d5 Mon Sep 17 00:00:00 2001 From: neminsheth Date: Fri, 12 Jul 2024 20:40:42 +0530 Subject: [PATCH 04/23] Working: TODO: Ensure Reset Password has Email verification --- .../modules/profile/views/profile_view.dart | 192 +++++++++++------- 1 file changed, 116 insertions(+), 76 deletions(-) diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index c26d11c1..e5be965f 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -1,5 +1,6 @@ // ignore_for_file: inference_failure_on_function_invocation +import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_ui_auth/firebase_ui_auth.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -17,11 +18,11 @@ class ProfileView extends GetView { Color get placeholderColor => Colors.grey; Widget _imageFrameBuilder( - BuildContext context, - Widget? child, - int? frame, - bool? _, - ) { + BuildContext context, + Widget? child, + int? frame, + bool? _, + ) { if (frame == null) { return Container(color: placeholderColor); } @@ -31,84 +32,96 @@ class ProfileView extends GetView { @override Widget build(BuildContext context) { - return Obx(() => profileScreen()); + return Obx(() => profileScreen(context)); } - Widget profileScreen() { + Widget profileScreen(BuildContext context) { return AuthService.to.isLoggedInValue ? ProfileScreen( - // We are using the Flutter Fire Profile Screen now but will change in subsequent steps. - // The issues are highlighted in comments here + // 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, + // 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, - 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, - ), - ), - ), + 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); - } - } - }) - ], - ) + ), + ), + ), + // 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(), + TextButton.icon( + onPressed: () => _resetPasswordEmailVerification(context), + label: const Text('Reset Password'), + icon: const Icon(Icons.email_rounded), + ), + 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); + } + else { + Get.snackbar( + 'Error', + 'Failed to pick image.', + snackPosition: SnackPosition.BOTTOM, + ); + } + } + }) + ], + ) : const Scaffold(); } @@ -121,4 +134,31 @@ class ProfileView extends GetView { textCancel: "Cancel", onConfirm: dlg.onSubmit); } + + Future _resetPasswordEmailVerification(BuildContext context) async { + final email = controller.currentUser?.email; + if (email != null) { + try { + await FirebaseAuth.instance.sendPasswordResetEmail(email: email); + controller.logout(); + Get.snackbar( + 'Success', + 'Password reset email sent. Please check your inbox.', + snackPosition: SnackPosition.BOTTOM, + ); + } catch (e) { + Get.snackbar( + 'Error', + 'Failed to send password reset email: $e', + snackPosition: SnackPosition.BOTTOM, + ); + } + } else { + Get.snackbar( + 'Error', + 'No email associated with this account.', + snackPosition: SnackPosition.BOTTOM, + ); + } + } } From 7f2c1667b5269469f69a30c10d2da6e9348511ee Mon Sep 17 00:00:00 2001 From: neminsheth Date: Fri, 12 Jul 2024 22:51:13 +0530 Subject: [PATCH 05/23] Working: TODO: Ensure Reset Password has Email verification --- .../modules/profile/views/profile_view.dart | 74 ++++++++++--------- lib/app/widgets/image_picker_button.dart | 35 +++++---- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index e5be965f..327a6193 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -92,48 +92,54 @@ class ProfileView extends GetView { //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(), - TextButton.icon( + // ? TextButton.icon( + // onPressed: callChangePwdDialog, + // label: const Text('Change Password'), + // icon: const Icon(Icons.password_rounded), + // ) + // : const SizedBox.shrink(), + ? TextButton.icon( onPressed: () => _resetPasswordEmailVerification(context), label: const Text('Reset Password'), icon: const Icon(Icons.email_rounded), - ), - 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); - } - else { - Get.snackbar( - 'Error', - 'Failed to pick image.', - snackPosition: SnackPosition.BOTTOM, - ); - } - } - }) + ) + : const SizedBox.shrink(), + // ImagePickerButton( + // callback: (String? path) async { + // if (path != null) { + // String? dest = await controller.uploadFile(path); + // if (dest != null) { + // await controller.updatePhotoURL(dest); + // } else { + // Get.snackbar( + // 'Error', + // 'Failed to upload image.', + // snackPosition: SnackPosition.BOTTOM, + // ); + // } + // } else { + // Get.snackbar( + // 'Error', + // 'Failed to pick image.', + // snackPosition: SnackPosition.BOTTOM, + // ); + // } + // }, + // ), ], ) : const Scaffold(); } - void callChangePwdDialog() { - var dlg = ChangePasswordDialog(controller.currentUser!); - Get.defaultDialog( - title: "Change Password", - content: dlg, - textConfirm: "Submit", - textCancel: "Cancel", - onConfirm: dlg.onSubmit); - } + // void callChangePwdDialog() { + // var dlg = ChangePasswordDialog(controller.currentUser!); + // Get.defaultDialog( + // title: "Change Password", + // content: dlg, + // textConfirm: "Submit", + // textCancel: "Cancel", + // onConfirm: dlg.onSubmit); + // } Future _resetPasswordEmailVerification(BuildContext context) async { final email = controller.currentUser?.email; diff --git a/lib/app/widgets/image_picker_button.dart b/lib/app/widgets/image_picker_button.dart index d6e87ff4..9082249e 100644 --- a/lib/app/widgets/image_picker_button.dart +++ b/lib/app/widgets/image_picker_button.dart @@ -24,14 +24,14 @@ enum ImageSources implements ActionEnum { case ImageSources.file: return await getFile(); default: + return null; } - return null; } @override - final IconData? icon; + final IconData icon; @override - final String? label; + final String label; static Future getImage(ImageSource imageSource) async { final pickedFile = await ImagePicker().pickImage(source: imageSource); @@ -53,7 +53,6 @@ enum ImageSources implements ActionEnum { 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; @@ -64,28 +63,36 @@ enum ImageSources implements ActionEnum { class ImagePickerButton extends MenuSheetButton { final ValueSetter? callback; - const ImagePickerButton( - {super.key, - super.icon = const Icon(Icons.image), - super.label = 'Pick an Image', - this.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); + if (callback != null && act != 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'), - ) + onPressed: () async { + var result = await ImageSources.getFile(); + if (result != null) { + callbackFunc(result); + } + }, + icon: icon, + label: const Text('Pick an Image'), + ) : builder(context); } } From 80a4999736033826ac14739ae509a802ccd95922 Mon Sep 17 00:00:00 2001 From: Anshuman Das Date: Sat, 13 Jul 2024 21:08:23 +0530 Subject: [PATCH 06/23] interim commit for merging PRs --- lib/app/modules/root/views/drawer.dart | 38 +++++----- lib/app/modules/root/views/root_view.dart | 12 +--- .../search/bindings/search_binding.dart | 12 ++++ .../search/controllers/search_controller.dart | 23 ++++++ lib/app/modules/search/views/search_view.dart | 24 +++++++ lib/app/routes/app_pages.dart | 9 ++- lib/app/routes/app_routes.dart | 2 + lib/app/widgets/login_widgets.dart | 30 ++++---- lib/app/widgets/menu_sheet_button.dart | 10 +-- lib/app/widgets/remotely_config_obx.dart | 71 +++++++++++++++++++ lib/app/widgets/screen_widget.dart | 30 ++++++++ lib/app/widgets/search_bar_button.dart | 3 + lib/models/access_level.dart | 2 +- lib/models/screens.dart | 59 ++++++++++----- lib/services/auth_service.dart | 9 +++ lib/services/remote_config.dart | 8 --- 16 files changed, 270 insertions(+), 72 deletions(-) create mode 100644 lib/app/modules/search/bindings/search_binding.dart create mode 100644 lib/app/modules/search/controllers/search_controller.dart create mode 100644 lib/app/modules/search/views/search_view.dart create mode 100644 lib/app/widgets/remotely_config_obx.dart create mode 100644 lib/app/widgets/search_bar_button.dart diff --git a/lib/app/modules/root/views/drawer.dart b/lib/app/modules/root/views/drawer.dart index 908d0223..ed5eb929 100644 --- a/lib/app/modules/root/views/drawer.dart +++ b/lib/app/modules/root/views/drawer.dart @@ -7,7 +7,8 @@ import '../../../../models/role.dart'; import '../../../../services/auth_service.dart'; import '../../../../models/screens.dart'; -import '../controllers/my_drawer_controller.dart'; +import '../../../../services/remote_config.dart'; +import '../../../widgets/remotely_config_obx.dart'; class DrawerWidget extends StatelessWidget { const DrawerWidget({ @@ -16,23 +17,26 @@ class DrawerWidget extends StatelessWidget { @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), - ), - )); + return RemotelyConfigObxVal.noparam( + (data) => 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, data), + ), + ), + List.empty().obs, + "useBottomSheetForProfileOptions", + Typer.boolean, + func: Screen.drawer, + ); } - List drawerItems(BuildContext context, Rx> values) { + List drawerItems(BuildContext context, Iterable values) { List list = [ Container( height: 100, @@ -67,7 +71,7 @@ class DrawerWidget extends StatelessWidget { } } - for (Screen screen in values.value) { + for (Screen screen in values) { list.add(ListTile( title: Text(screen.label ?? ''), onTap: () { diff --git a/lib/app/modules/root/views/root_view.dart b/lib/app/modules/root/views/root_view.dart index 2bbf228c..2173aa8d 100644 --- a/lib/app/modules/root/views/root_view.dart +++ b/lib/app/modules/root/views/root_view.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:get_flutter_fire/services/auth_service.dart'; import '../../../routes/app_pages.dart'; import '../../../../models/screens.dart'; +import '../../../widgets/screen_widget.dart'; import '../controllers/root_controller.dart'; import 'drawer.dart'; @@ -38,7 +39,7 @@ class RootView extends GetView { ? controller.openDrawer() : {Screen.HOME.doAction()}, ), - actions: topRightMenuButtons(current), + actions: ScreenWidgetExtension.topRightMenuButtons(current), // automaticallyImplyLeading: false, //removes drawer icon ), body: GetRouterOutlet( @@ -52,13 +53,4 @@ class RootView extends GetView { }, ); } - -//This could be used to add icon buttons in expanded web view instead of the context menu - List topRightMenuButtons(GetNavConfig current) { - return [ - Container( - margin: const EdgeInsets.only(right: 15), - child: Screen.LOGIN.widget(current)) - ]; //TODO add seach button - } } diff --git a/lib/app/modules/search/bindings/search_binding.dart b/lib/app/modules/search/bindings/search_binding.dart new file mode 100644 index 00000000..64cfa36f --- /dev/null +++ b/lib/app/modules/search/bindings/search_binding.dart @@ -0,0 +1,12 @@ +import 'package:get/get.dart'; + +import '../controllers/search_controller.dart'; + +class SearchBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut( + () => SearchController(), + ); + } +} diff --git a/lib/app/modules/search/controllers/search_controller.dart b/lib/app/modules/search/controllers/search_controller.dart new file mode 100644 index 00000000..f282fabb --- /dev/null +++ b/lib/app/modules/search/controllers/search_controller.dart @@ -0,0 +1,23 @@ +import 'package:get/get.dart'; + +class SearchController extends GetxController { + //TODO: Implement SearchController + + final count = 0.obs; + @override + void onInit() { + super.onInit(); + } + + @override + void onReady() { + super.onReady(); + } + + @override + void onClose() { + super.onClose(); + } + + void increment() => count.value++; +} diff --git a/lib/app/modules/search/views/search_view.dart b/lib/app/modules/search/views/search_view.dart new file mode 100644 index 00000000..f0c3c16c --- /dev/null +++ b/lib/app/modules/search/views/search_view.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart' hide SearchController; + +import 'package:get/get.dart'; + +import '../controllers/search_controller.dart'; + +class SearchView extends GetView { + const SearchView({Key? key}) : super(key: key); + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('SearchView'), + centerTitle: true, + ), + body: const Center( + child: Text( + 'SearchView is working', + style: TextStyle(fontSize: 20), + ), + ), + ); + } +} diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 7269755d..068e4cb4 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; + import 'package:get/get.dart'; import '../../models/access_level.dart'; import '../../models/role.dart'; +import '../../models/screens.dart'; import '../middleware/auth_middleware.dart'; import '../modules/cart/bindings/cart_binding.dart'; import '../modules/cart/views/cart_view.dart'; @@ -28,6 +30,8 @@ import '../modules/register/bindings/register_binding.dart'; import '../modules/register/views/register_view.dart'; import '../modules/root/bindings/root_binding.dart'; import '../modules/root/views/root_view.dart'; +import '../modules/search/bindings/search_binding.dart'; +import '../modules/search/views/search_view.dart'; import '../modules/settings/bindings/settings_binding.dart'; import '../modules/settings/views/settings_view.dart'; import '../modules/task_details/bindings/task_details_binding.dart'; @@ -36,7 +40,6 @@ import '../modules/tasks/bindings/tasks_binding.dart'; 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'; part 'app_routes.dart'; part 'screen_extension.dart'; @@ -150,5 +153,9 @@ class AppPages { ) ], ), + Screen.SEARCH.getPage( + page: () => const SearchView(), + binding: SearchBinding(), + ), ]; } diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index f3129d21..7391dcc0 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -30,6 +30,7 @@ abstract class Routes { '${Screen.LOGIN.route}?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}'; static String REGISTER_THEN(String afterSuccessfulLogin) => '${Screen.REGISTER.route}?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}'; + // static const SEARCH = _Paths.SEARCH; } // Keeping this as Get_Cli will require it. Any addition can later be added to Screen @@ -51,4 +52,5 @@ abstract class _Paths { // static const USERS = '/users'; // static const USER_PROFILE = '/:uId'; // static const MY_PRODUCTS = '/my-products'; + // static const SEARCH = '/search'; } diff --git a/lib/app/widgets/login_widgets.dart b/lib/app/widgets/login_widgets.dart index b8f2d8c1..35e7d153 100644 --- a/lib/app/widgets/login_widgets.dart +++ b/lib/app/widgets/login_widgets.dart @@ -7,6 +7,7 @@ import '../../services/auth_service.dart'; import '../../models/screens.dart'; import '../../services/remote_config.dart'; import 'menu_sheet_button.dart'; +import 'remotely_config_obx.dart'; class LoginWidgets { static Widget headerBuilder(context, constraints, shrinkOffset) { @@ -56,31 +57,36 @@ class LoginBottomSheetToggle extends MenuSheetButton { @override Icon? get icon => (AuthService.to.isLoggedInValue) - ? values.length == 1 + ? 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 + ? values.length <= 1 ? 'Logout' : 'Click for Options' : 'Login'; + @override + void buttonPressed(Iterable values) async => values.isEmpty + ? callbackFunc(await Screen.LOGOUT.doAction()) + : super.buttonPressed(values); + @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)})); + MenuItemsController controller = + MenuItemsController(const Iterable.empty()); return Obx(() => (AuthService.to.isLoggedInValue) - ? builder(context, vals: controller.values.value) + ? RemotelyConfigObx( + () => builder(context, vals: controller.values.value), + controller, + Screen.sheet, + Screen.NONE, + "useBottomSheetForProfileOptions", + Typer.boolean, + ) : !(current.currentPage!.name == Screen.LOGIN.path) ? IconButton( onPressed: () async { diff --git a/lib/app/widgets/menu_sheet_button.dart b/lib/app/widgets/menu_sheet_button.dart index abd3873e..31649e4d 100644 --- a/lib/app/widgets/menu_sheet_button.dart +++ b/lib/app/widgets/menu_sheet_button.dart @@ -2,11 +2,11 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../models/action_enum.dart'; +import 'remotely_config_obx.dart'; -class MenuItemsController extends GetxController { - MenuItemsController(Iterable iter) : values = Rx>(iter); - - final Rx> values; +class MenuItemsController + extends RemoteConfigController> { + MenuItemsController(super.iter); } class MenuSheetButton extends StatelessWidget { @@ -65,7 +65,7 @@ class MenuSheetButton extends StatelessWidget { //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 || + return values.length <= 1 || Get.mediaQuery.orientation == Orientation.portrait // : Get.context!.isPortrait ? (icon != null diff --git a/lib/app/widgets/remotely_config_obx.dart b/lib/app/widgets/remotely_config_obx.dart new file mode 100644 index 00000000..a1ea63db --- /dev/null +++ b/lib/app/widgets/remotely_config_obx.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../services/remote_config.dart'; + +class RemoteConfigController extends GetxController { + RemoteConfigController(L iter) : values = Rx(iter); + final Rx values; +} + +/// final _name = "GetX".obs; +/// Obx(() => Text( _name.value )),... ; +class RemotelyConfigObx>> + extends ObxWidget { + final Widget Function() builder; + final X param; + final C controller; + final String config; + final Typer configType; + final Future Function(X) func; + + RemotelyConfigObx(this.builder, this.controller, this.func, this.param, + this.config, this.configType, + {super.key}) { + Get.put(controller, permanent: true); //must make true else gives error + func(param).then((v) { + controller.values.value = v; + }); + RemoteConfig.instance.then((ins) => ins.addListener(config, configType, + (val) async => {controller.values.value = await func(param)})); + } + + @override + Widget build() => builder(); +} + +/// Similar to Obx, but manages a local state. +/// Pass the initial data in constructor. +/// Useful for simple local states, like toggles, visibility, themes, +/// button states, etc. +/// Sample: +/// ObxValue((data) => Switch( +/// value: data.value, +/// onChanged: (flag) => data.value = flag, +/// ), +/// false.obs, +/// ), +class RemotelyConfigObxVal extends ObxWidget { + final Widget Function(T) builder; + final T data; + final String config; + final Typer configType; + + RemotelyConfigObxVal(this.builder, this.data, this.config, this.configType, + {super.key, required Future Function(X) func, required X param}) { + func(param).then((v) => {data.value = v}); + RemoteConfig.instance.then((ins) => ins.addListener( + config, configType, (val) async => {data.value = await func(param)})); + } + + RemotelyConfigObxVal.noparam( + this.builder, this.data, this.config, this.configType, + {super.key, required Future Function() func}) { + func().then((v) => {data.value = v}); + RemoteConfig.instance.then((ins) => ins.addListener( + config, configType, (val) async => {data.value = await func()})); + } + + @override + Widget build() => builder(data); +} diff --git a/lib/app/widgets/screen_widget.dart b/lib/app/widgets/screen_widget.dart index d80c9275..edb4ead1 100644 --- a/lib/app/widgets/screen_widget.dart +++ b/lib/app/widgets/screen_widget.dart @@ -3,6 +3,7 @@ import 'package:get/get.dart'; import '../routes/app_pages.dart'; import '../../models/role.dart'; import '../../models/screens.dart'; +import 'login_widgets.dart'; class ScreenWidget extends StatelessWidget { final Widget body; @@ -73,3 +74,32 @@ class ScreenWidget extends StatelessWidget { return null; //TODO multi fab button on press } } + +extension ScreenWidgetExtension on Screen { + Widget? widget(GetNavConfig current) { + //those with accessor == widget must be handled here + switch (this) { + case Screen.SEARCH: + return IconButton(onPressed: () => {}, icon: Icon(icon)); + case Screen.LOGIN: + return LoginBottomSheetToggle(current); + case Screen.LOGOUT: + return LoginBottomSheetToggle(current); + default: + } + return null; + } + +//This could be used to add icon buttons in expanded web view instead of the context menu + static List topRightMenuButtons(GetNavConfig current) { + List widgets = []; + Screen.topRightMenu().then((v) { + for (var screen in v) { + widgets.add(Container( + margin: const EdgeInsets.only(right: 15), + child: screen.widget(current))); + } + }); + return widgets; //This will return empty. We need a Obx + } +} diff --git a/lib/app/widgets/search_bar_button.dart b/lib/app/widgets/search_bar_button.dart new file mode 100644 index 00000000..14f60d37 --- /dev/null +++ b/lib/app/widgets/search_bar_button.dart @@ -0,0 +1,3 @@ +// This uses Remote Config to know where to locate the search button +// If on top, then it expands to title area on press in mobiles and is already expanded in web +// If on Nav Bar, the it initiates a SearchAnchor as a bottomsheet in mobile and like a drawer/nav column in web \ No newline at end of file diff --git a/lib/models/access_level.dart b/lib/models/access_level.dart index a7b89742..20b79252 100644 --- a/lib/models/access_level.dart +++ b/lib/models/access_level.dart @@ -1,7 +1,7 @@ enum AccessLevel { + notAuthed, // used for login screens 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 diff --git a/lib/models/screens.dart b/lib/models/screens.dart index 24dee39f..eb89b5a5 100644 --- a/lib/models/screens.dart +++ b/lib/models/screens.dart @@ -1,6 +1,5 @@ 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'; @@ -8,9 +7,13 @@ 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 + widget, + topRight, + topCenter, + topLeft, + topBar, //bar below the main top menu bar + navigator, //bottom nav. can be linked to drawer items. left strip in expanded web //handled in ScreenWidget + drawer, //creates nav tree. persistant in expanded web and linked with nav icons //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 @@ -18,6 +21,7 @@ enum AccessedVia { } enum Screen implements ActionEnum { + NONE.none(), //null HOME('/home', icon: Icons.home, label: "Home", @@ -37,22 +41,18 @@ enum Screen implements ActionEnum { 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), + remoteConfig: "useBottomSheetForProfileOptions"), SETTINGS('/settings', icon: Icons.settings, label: "Settings", accessor_: AccessedVia.drawer, accessLevel: AccessLevel.authenticated, - remoteConfig: true), + remoteConfig: "useBottomSheetForProfileOptions"), CART('/cart', icon: Icons.trolley, label: "Cart", @@ -96,20 +96,40 @@ enum Screen implements ActionEnum { accessLevel: AccessLevel.roleBased), MY_PRODUCT_DETAILS('/:productId', parent: MY_PRODUCTS, accessLevel: AccessLevel.roleBased), + SEARCH('/search', + icon: Icons.search, + label: "Search", + accessor_: AccessedVia.topRight, + remoteConfig: "showSearchBarOnTop", + accessLevel: AccessLevel.public), LOGOUT('/login', icon: Icons.logout, label: "Logout", - accessor_: AccessedVia.bottomSheet, + accessor_: AccessedVia.topRight, + remoteConfig: "useBottomSheetForProfileOptions", accessLevel: AccessLevel.authenticated), + LOGIN('/login', + icon: Icons.login, + accessor_: AccessedVia.topRight, + accessLevel: AccessLevel.notAuthed), ; const Screen(this.path, {this.icon, this.label, - this.parent, + this.parent = Screen.NONE, this.accessor_ = AccessedVia.singleTap, this.accessLevel = AccessLevel.authenticated, - this.remoteConfig = false}); + this.remoteConfig}); + + const Screen.none() + : path = '', + icon = null, + label = null, + parent = null, + accessor_ = AccessedVia.singleTap, + accessLevel = AccessLevel.authenticated, + remoteConfig = null; @override final IconData? icon; @@ -121,10 +141,10 @@ enum Screen implements ActionEnum { final Screen? parent; final AccessLevel accessLevel; //if false it is role based. true means allowed for all - final bool remoteConfig; + final String? remoteConfig; Future get accessor async { - if (remoteConfig && + if (remoteConfig == "useBottomSheetForProfileOptions" && (await RemoteConfig.instance).useBottomSheetForProfileOptions()) { return AccessedVia.bottomSheet; } @@ -164,6 +184,12 @@ enum Screen implements ActionEnum { return list; } + static Future> topRightMenu() async { + return Screen.values.where((Screen screen) => + screen.accessor_ == AccessedVia.topRight && + AuthService.to.accessLevel.index >= screen.accessLevel.index); + } + @override Future doAction() async { if (this == LOGOUT) { @@ -171,7 +197,4 @@ enum Screen implements ActionEnum { } Get.rootDelegate.toNamed(route); } - - Widget? widget(GetNavConfig current) => - (this == LOGIN) ? LoginBottomSheetToggle(current) : null; } diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 8bf72aaa..a6bef783 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -5,6 +5,7 @@ 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 'package:get_flutter_fire/models/access_level.dart'; import '../models/screens.dart'; import '../constants.dart'; @@ -37,6 +38,14 @@ class AuthService extends GetxService { }); } + AccessLevel get accessLevel => user != null + ? user!.isAnonymous + ? _userRole.value.index > Role.buyer.index + ? AccessLevel.roleBased + : AccessLevel.authenticated + : AccessLevel.guest + : AccessLevel.public; + bool get isEmailVerified => user != null && (user!.email == null || user!.emailVerified); diff --git a/lib/services/remote_config.dart b/lib/services/remote_config.dart index 5d1145a5..cb2a8928 100644 --- a/lib/services/remote_config.dart +++ b/lib/services/remote_config.dart @@ -13,7 +13,6 @@ class RemoteConfig { } final FirebaseRemoteConfig _remoteConfig = FirebaseRemoteConfig.instance; - final List listeners = []; Future init() async { await _remoteConfig.setConfigSettings(RemoteConfigSettings( @@ -68,11 +67,4 @@ class RemoteConfig { bool showSearchBarOnTop() { return _remoteConfig.getBool("showSearchBarOnTop"); } - - void addUseBottomSheetForProfileOptionsListener(listener) { - addListener("useBottomSheetForProfileOptions", Typer.boolean, listener); - if (!listeners.contains(listener)) { - listeners.add(listener); - } - } } From 038adb5b345087423022a0e358fab8b9dd24010f Mon Sep 17 00:00:00 2001 From: neminsheth Date: Sun, 14 Jul 2024 01:02:39 +0530 Subject: [PATCH 07/23] Fix null check error in ImagePickerButton and improve null handling in ProfileView and ProfileController --- .../modules/profile/views/profile_view.dart | 48 ++++------------- lib/app/widgets/image_picker_button.dart | 54 ++++++++++++------- 2 files changed, 45 insertions(+), 57 deletions(-) diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index 327a6193..764954b8 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -92,54 +92,28 @@ class ProfileView extends GetView { //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(), ? TextButton.icon( onPressed: () => _resetPasswordEmailVerification(context), label: const Text('Reset Password'), icon: const Icon(Icons.email_rounded), ) : const SizedBox.shrink(), - // ImagePickerButton( - // callback: (String? path) async { - // if (path != null) { - // String? dest = await controller.uploadFile(path); - // if (dest != null) { - // await controller.updatePhotoURL(dest); - // } else { - // Get.snackbar( - // 'Error', - // 'Failed to upload image.', - // snackPosition: SnackPosition.BOTTOM, - // ); - // } - // } else { - // Get.snackbar( - // 'Error', - // 'Failed to pick image.', - // snackPosition: SnackPosition.BOTTOM, - // ); - // } - // }, - // ), + 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); + } + } + }) ], ) : const Scaffold(); } - // void callChangePwdDialog() { - // var dlg = ChangePasswordDialog(controller.currentUser!); - // Get.defaultDialog( - // title: "Change Password", - // content: dlg, - // textConfirm: "Submit", - // textCancel: "Cancel", - // onConfirm: dlg.onSubmit); - // } + Future _resetPasswordEmailVerification(BuildContext context) async { final email = controller.currentUser?.email; diff --git a/lib/app/widgets/image_picker_button.dart b/lib/app/widgets/image_picker_button.dart index 9082249e..dbd504ef 100644 --- a/lib/app/widgets/image_picker_button.dart +++ b/lib/app/widgets/image_picker_button.dart @@ -24,14 +24,14 @@ enum ImageSources implements ActionEnum { case ImageSources.file: return await getFile(); default: - return null; } + return null; } @override - final IconData icon; + final IconData? icon; @override - final String label; + final String? label; static Future getImage(ImageSource imageSource) async { final pickedFile = await ImagePicker().pickImage(source: imageSource); @@ -44,14 +44,37 @@ enum ImageSources implements ActionEnum { } static Future getFile() async { - FilePickerResult? result = await FilePicker.platform - .pickFiles(type: FileType.image, allowMultiple: false); + if (GetPlatform.isWeb) { + // Web-specific file picking logic + return await getWebFile(); + } else { + 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; + } else { + Get.snackbar('Error', 'Image Not Selected'); + return null; + } + } + } + + static Future getWebFile() 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; } else { Get.snackbar('Error', 'Image Not Selected'); @@ -75,24 +98,15 @@ class ImagePickerButton extends MenuSheetButton { @override void callbackFunc(act) { - if (callback != null && act != null) { - callback!(act); - } + if (callback != null) callback!(act); } @override Widget build(BuildContext context) { - return !(GetPlatform.isAndroid || GetPlatform.isIOS) - ? TextButton.icon( - onPressed: () async { - var result = await ImageSources.getFile(); - if (result != null) { - callbackFunc(result); - } - }, + return TextButton.icon( + onPressed: () async => callbackFunc(await ImageSources.getFile()), icon: icon, label: const Text('Pick an Image'), - ) - : builder(context); + ); } -} +} \ No newline at end of file From 50e9bdb32eab0603f1d4fbaf29e376aa88d8030b Mon Sep 17 00:00:00 2001 From: Hardik Date: Sun, 14 Jul 2024 22:19:54 +0530 Subject: [PATCH 08/23] fix: bottom navigation current index --- lib/app/routes/screen_extension.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/app/routes/screen_extension.dart b/lib/app/routes/screen_extension.dart index aaf138b0..8b4cad98 100644 --- a/lib/app/routes/screen_extension.dart +++ b/lib/app/routes/screen_extension.dart @@ -110,13 +110,13 @@ extension ScreenExtension on Screen { extension RoleExtension on Role { int getCurrentIndexFromRoute(GetNavConfig? currentRoute) { - final String? currentLocation = currentRoute?.location; + final String? currentLocation = currentRoute?.uri.toString(); int currentIndex = 0; if (currentLocation != null) { currentIndex = - tabs.indexWhere((tab) => currentLocation.startsWith(tab.path)); + tabs.indexWhere((tab) => currentLocation.endsWith(tab.path)); } - return (currentIndex > 0) ? currentIndex : 0; + return (currentIndex >= 0) ? currentIndex : 0; } void routeTo(int value, GetDelegate delegate) { From c1fedc493808390135d2a9826cc9f532e30afa35 Mon Sep 17 00:00:00 2001 From: Hardik Date: Mon, 15 Jul 2024 02:32:33 +0530 Subject: [PATCH 09/23] fix: handled bottom nav index for path & query parameters --- lib/app/routes/screen_extension.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/app/routes/screen_extension.dart b/lib/app/routes/screen_extension.dart index 8b4cad98..e334c4e9 100644 --- a/lib/app/routes/screen_extension.dart +++ b/lib/app/routes/screen_extension.dart @@ -113,10 +113,14 @@ extension RoleExtension on Role { final String? currentLocation = currentRoute?.uri.toString(); int currentIndex = 0; if (currentLocation != null) { - currentIndex = - tabs.indexWhere((tab) => currentLocation.endsWith(tab.path)); + // removinng '/home' from the start of the location + final filteredLocation = + currentLocation.replaceFirst(RegExp(r'^/home'), ''); + currentIndex = tabs.indexWhere((tab) { + return filteredLocation.startsWith(tab.path); + }); } - return (currentIndex >= 0) ? currentIndex : 0; + return (currentIndex > 0) ? currentIndex : 0; } void routeTo(int value, GetDelegate delegate) { From ad6278cf8bf256c1ac7923572f676d80a485b94d Mon Sep 17 00:00:00 2001 From: Aastha Gadhvi Date: Mon, 15 Jul 2024 15:55:43 +0530 Subject: [PATCH 10/23] added image picker --- ios/Flutter/Generated.xcconfig | 14 +++ ios/Flutter/flutter_export_environment.sh | 13 +++ ios/Runner/GeneratedPluginRegistrant.h | 19 ++++ ios/Runner/GeneratedPluginRegistrant.m | 91 +++++++++++++++++++ .../ephemeral/Flutter-Generated.xcconfig | 11 +++ .../ephemeral/flutter_export_environment.sh | 12 +++ 6 files changed, 160 insertions(+) create mode 100644 ios/Flutter/Generated.xcconfig create mode 100644 ios/Flutter/flutter_export_environment.sh create mode 100644 ios/Runner/GeneratedPluginRegistrant.h create mode 100644 ios/Runner/GeneratedPluginRegistrant.m create mode 100644 macos/Flutter/ephemeral/Flutter-Generated.xcconfig create mode 100644 macos/Flutter/ephemeral/flutter_export_environment.sh diff --git a/ios/Flutter/Generated.xcconfig b/ios/Flutter/Generated.xcconfig new file mode 100644 index 00000000..ebe7b0ca --- /dev/null +++ b/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter +FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 00000000..e9e43111 --- /dev/null +++ b/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter" +export "FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/ios/Runner/GeneratedPluginRegistrant.h b/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 00000000..7a890927 --- /dev/null +++ b/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/ios/Runner/GeneratedPluginRegistrant.m b/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 00000000..11a184c0 --- /dev/null +++ b/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,91 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import desktop_webview_auth; +#endif + +#if __has_include() +#import +#else +@import file_picker; +#endif + +#if __has_include() +#import +#else +@import firebase_analytics; +#endif + +#if __has_include() +#import +#else +@import firebase_auth; +#endif + +#if __has_include() +#import +#else +@import firebase_core; +#endif + +#if __has_include() +#import +#else +@import firebase_dynamic_links; +#endif + +#if __has_include() +#import +#else +@import firebase_remote_config; +#endif + +#if __has_include() +#import +#else +@import firebase_storage; +#endif + +#if __has_include() +#import +#else +@import google_sign_in_ios; +#endif + +#if __has_include() +#import +#else +@import image_picker_ios; +#endif + +#if __has_include() +#import +#else +@import path_provider_foundation; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [DesktopWebviewAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"DesktopWebviewAuthPlugin"]]; + [FilePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FilePickerPlugin"]]; + [FLTFirebaseAnalyticsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAnalyticsPlugin"]]; + [FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]]; + [FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]]; + [FLTFirebaseDynamicLinksPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseDynamicLinksPlugin"]]; + [FLTFirebaseRemoteConfigPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseRemoteConfigPlugin"]]; + [FLTFirebaseStoragePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseStoragePlugin"]]; + [FLTGoogleSignInPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTGoogleSignInPlugin"]]; + [FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]]; + [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]]; +} + +@end diff --git a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 00000000..75656d0a --- /dev/null +++ b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter +FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/macos/Flutter/ephemeral/flutter_export_environment.sh b/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100644 index 00000000..accf248b --- /dev/null +++ b/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter" +export "FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" From 4125c29af001a127c664c9a62b732d39128627d3 Mon Sep 17 00:00:00 2001 From: Aastha Gadhvi Date: Mon, 15 Jul 2024 16:22:29 +0530 Subject: [PATCH 11/23] change readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be46f067..7d403519 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Step 5: Add Guest User/Anonymous login with a Cart and Checkout use case [https: * delete unlinked anonymous user post logout -Step 6: Add ImagePicker and Firebase Storage for profile image +Step 6: Add ImagePicker and Firebase Storage for profile image (Done) * Create PopupMenu button for web [https://api.flutter.dev/flutter/material/PopupMenuButton-class.html] * BottomSheet for phones and single file button for desktops From 08eba7d126c0d5003158019c7172c25f26545a83 Mon Sep 17 00:00:00 2001 From: vedantbhawnani Date: Mon, 15 Jul 2024 21:38:21 +0530 Subject: [PATCH 12/23] TODO 14 --- .gitignore | 3 + ios/Runner/Info.plist | 16 ++ lib/app/modules/login/views/custom_login.dart | 257 ++++++++++++++++++ .../modules/login/views/custom_signUp.dart | 205 ++++++++++++++ lib/app/modules/login/views/login_view.dart | 77 +++--- lib/app/routes/app_pages.dart | 5 + lib/models/screens.dart | 5 + lib/services/auth_service.dart | 106 +++++++- pubspec.lock | 24 ++ pubspec.yaml | 1 + 10 files changed, 663 insertions(+), 36 deletions(-) create mode 100644 lib/app/modules/login/views/custom_login.dart create mode 100644 lib/app/modules/login/views/custom_signUp.dart diff --git a/.gitignore b/.gitignore index c9583676..c19fdafb 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,8 @@ migrate_working_dir/ .pub/ /build/ +node_modules + # Symbolication related app.*.symbols @@ -65,6 +67,7 @@ ios/Flutter/Debug.xcconfig ios/Flutter/Release.xcconfig ios/Runner/AppDelegate.swift ios/Runner/Runner-Bridging-Header.h +ios/Runner/GoogleService-Info.plist ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index fc7f1dd4..3d1ee42c 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -52,4 +52,20 @@ NSPhotoLibraryUsageDescription Allow access to photo library + + +CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + + + com.googleusercontent.apps.260821266676-n1dskq31gq05s8egsuemfl2slek3vd9b + + + + diff --git a/lib/app/modules/login/views/custom_login.dart b/lib/app/modules/login/views/custom_login.dart new file mode 100644 index 00000000..d9e946ca --- /dev/null +++ b/lib/app/modules/login/views/custom_login.dart @@ -0,0 +1,257 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../../../models/screens.dart'; +import '../../../../services/auth_service.dart'; + +class CustomSignIn extends StatelessWidget { + const CustomSignIn({super.key}); + + @override + Widget build(BuildContext context) { + final height = MediaQuery.of(context).size.height; + final width = MediaQuery.of(context).size.width; + + final emailController = TextEditingController(); + final passwordController = TextEditingController(); + + return Scaffold( + backgroundColor: Colors.grey[300], + body: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: height * 0.02), + //logo + Image.asset( + 'assets/icons/logo.png', + height: height * 0.25, + width: width * 0.25, + ), + + SizedBox( + height: height * 0.02, + ), + + // welcome back + const Text("You were missed! Welcome Back"), + SizedBox(height: height * 0.02), + + //username textfield + InputWidget( + width: width, + emailController: emailController, + hintText: 'Email ID', + obscureText: false, + keyboardType: TextInputType.emailAddress, + ), + SizedBox(height: height * 0.02), + //password textfield + InputWidget( + width: width, + emailController: passwordController, + hintText: 'Password', + obscureText: true, + ), + + //forgot password? + Padding( + padding: EdgeInsets.only(right: width * 0.055), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () { + TextEditingController resetController = + TextEditingController(); + Get.defaultDialog( + title: "Reset Passsword", + content: Column( + children: [ + const Text("Enter your Email-ID"), + InputWidget( + width: width, + emailController: resetController, + hintText: "Email", + obscureText: false), + ], + ), + actions: [ + TextButton( + child: const Text("Cancel"), + onPressed: () { + Get.back(); + }, + ), + TextButton( + child: const Text('Send Reset Link'), + onPressed: () async { + try { + await AuthService().resetPassword( + email: resetController.text.trim()); + Get.snackbar('Password Reset', + 'A password reset link has been sent to your email.'); + Get.back(); // Close dialog using GetX + } catch (e) { + Get.snackbar( + 'Error', 'Failed to send reset link.'); + log("Error sending reset link: $e"); + } + }, + ), + ], + ); + }, + child: Text( + "Forgot Password?", + style: TextStyle(color: Colors.grey.shade600), + )), + ], + ), + ), + //sign in button + GestureDetector( + onTap: () { + if (emailController.text.isEmpty || + !emailController.text.contains('@')) { + Get.snackbar( + 'Invalid Email', + "Please enter a valid email id.", + ); + } else if (passwordController.text.isEmpty || + passwordController.text.length < 6) { + Get.snackbar( + 'Invalid Password', + "Please enter a password longer than 6 letters.", + ); + } else if (emailController.text.isNotEmpty && + passwordController.text.isNotEmpty) { + AuthService() + .login(emailController.text, passwordController.text); + } + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: width * 0.05), + margin: EdgeInsets.symmetric(horizontal: width * 0.1), + height: height * 0.07, + width: width * 0.2, + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Text("Sign In", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18))), + ), + ), + + SizedBox(height: height * 0.05), + + //or continue with + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: width * 0.2, + child: Divider( + thickness: 0.5, + color: Colors.grey.shade900, + )), + SizedBox( + width: width * 0.05, + ), + const Text("Or Continue with"), + SizedBox( + width: width * 0.05, + ), + SizedBox( + width: width * 0.2, + child: Divider( + thickness: 0.5, + color: Colors.grey.shade900, + )), + ], + ), + + SizedBox(height: height * 0.02), + + //google sign in + GestureDetector( + onTap: () => AuthService().signInwithGoogle(), + child: Container( + padding: EdgeInsets.all(width * 0.03), + margin: EdgeInsets.symmetric(horizontal: width * 0.08), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(10), + ), + child: Image.asset('assets/icons/google.png', + height: height * 0.045), + ), + ), + + SizedBox(height: height * 0.02), + + //register now / sign up now + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('New user?'), + GestureDetector( + onTap: () { + Get.rootDelegate.toNamed(Screen.SIGNUP.route); + }, + child: const Text(' Register now', + style: TextStyle(color: Colors.blue))), + ], + ), + const SizedBox( + height: 40, + ), + ], + ), + ), + ), + ); + } +} + +class InputWidget extends StatelessWidget { + const InputWidget( + {super.key, + required this.width, + required this.emailController, + required this.hintText, + required this.obscureText, + this.keyboardType}); + + final double width; + final TextEditingController emailController; + final String hintText; + final bool obscureText; + final TextInputType? keyboardType; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: width * 0.08), + child: TextField( + controller: emailController, + decoration: InputDecoration( + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.grey.shade400)), + fillColor: Colors.grey.shade200, + filled: true, + hintText: hintText), + obscureText: obscureText, + ), + ); + } +} diff --git a/lib/app/modules/login/views/custom_signUp.dart b/lib/app/modules/login/views/custom_signUp.dart new file mode 100644 index 00000000..4de191ee --- /dev/null +++ b/lib/app/modules/login/views/custom_signUp.dart @@ -0,0 +1,205 @@ +// ignore_for_file: file_names + +import 'package:firebase_ui_auth/firebase_ui_auth.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../../../models/screens.dart'; +import '../../../../services/auth_service.dart'; + +class CustomSignUp extends GetView { + const CustomSignUp({super.key}); + + @override + Widget build(BuildContext context) { + final height = MediaQuery.of(context).size.height; + final width = MediaQuery.of(context).size.width; + + final emailController = TextEditingController(); + final passwordController = TextEditingController(); + final confirmpasswordController = TextEditingController(); + return Scaffold( + backgroundColor: Colors.grey[300], + body: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: height * 0.02), + + //logo + Image.asset( + 'assets/icons/logo.png', + height: height * 0.2, + width: width * 0.2, + ), + + SizedBox(height: height * 0.01), + + // welcome back + const Text("Welcome Aboard! Let's have a great time."), + SizedBox(height: height * 0.02), + + //username textfield + InputWidget( + width: width, + emailController: emailController, + hintText: 'Email ID', + obscureText: false, + ), + SizedBox(height: height * 0.01), + //password textfield + InputWidget( + width: width, + emailController: passwordController, + hintText: 'Password', + obscureText: true, + ), + SizedBox(height: height * 0.01), + //password textfield + InputWidget( + width: width, + emailController: confirmpasswordController, + hintText: 'Confirm Password', + obscureText: true, + ), + SizedBox(height: height * 0.03), + + //sign in button + GestureDetector( + onTap: () { + if (emailController.text.isEmpty || + !emailController.text.contains('@')) { + Get.snackbar( + 'Invalid Email', + "Please enter a valid email id.", + ); + } else if (passwordController.text.isEmpty || + passwordController.text.length < 6) { + Get.snackbar( + 'Invalid Password', + "Please enter a password longer than 6 letters.", + ); + } else if (passwordController.text == + confirmpasswordController.text) { + AuthService() + .login(emailController.text, passwordController.text); + } + }, + child: Container( + padding: EdgeInsets.all(width * 0.05), + margin: EdgeInsets.symmetric(horizontal: width * 0.1), + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Text("Sign Up", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 18))), + ), + ), + + SizedBox(height: height * 0.05), + + // //or continue with + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // SizedBox( + // width: width * 0.2, + // child: Divider( + // thickness: 0.5, + // color: Colors.grey.shade900, + // )), + // SizedBox( + // width: width * 0.05, + // ), + // const Text("Or Continue with"), + // SizedBox( + // width: width * 0.05, + // ), + // SizedBox( + // width: width * 0.2, + // child: Divider( + // thickness: 0.5, + // color: Colors.grey.shade900, + // )), + // ], + // ), + + // SizedBox(height: height * 0.01), + + // //google sign in + // GestureDetector( + // onTap: () => AuthService().signInwithGoogle(), + // child: Container( + // padding: EdgeInsets.all(width * 0.03), + // margin: EdgeInsets.symmetric(horizontal: width * 0.1), + // decoration: BoxDecoration( + // color: Colors.grey.shade200, + // borderRadius: BorderRadius.circular(10), + // ), + // child: Image.asset('assets/icons/google.png', + // height: height * 0.045), + // ), + // ), + + SizedBox(height: height * 0.01), + + //register now / sign up now + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Exisiting user?'), + GestureDetector( + onTap: () { + Get.rootDelegate.toNamed(Screen.LOGIN.route); + // print(Get.rootDelegate.history); + }, + child: const Text(' Sign In', + style: TextStyle(color: Colors.blue))), + ], + ), + SizedBox(height: height * 0.1) + ], + ), + ), + ), + ); + } +} + +class InputWidget extends StatelessWidget { + const InputWidget( + {super.key, + required this.width, + required this.emailController, + required this.hintText, + required this.obscureText}); + + final double width; + final TextEditingController emailController; + final String hintText; + final bool obscureText; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: width * 0.08), + child: TextField( + controller: emailController, + decoration: InputDecoration( + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.white)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.grey.shade400)), + fillColor: Colors.grey.shade200, + filled: true, + hintText: hintText), + obscureText: obscureText, + ), + ); + } +} diff --git a/lib/app/modules/login/views/login_view.dart b/lib/app/modules/login/views/login_view.dart index 00c3af3f..010a7cf7 100644 --- a/lib/app/modules/login/views/login_view.dart +++ b/lib/app/modules/login/views/login_view.dart @@ -1,15 +1,15 @@ -// ignore_for_file: inference_failure_on_function_invocation +// ignore_for_file: inference_failure_on_function_invocation, non_constant_identifier_names import 'package:firebase_auth/firebase_auth.dart' as fba; 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'; -import '../../../../firebase_options.dart'; import '../../../../models/screens.dart'; import '../../../widgets/login_widgets.dart'; import '../controllers/login_controller.dart'; +import 'custom_login.dart'; +import 'custom_signUp.dart'; class LoginView extends GetView { void showReverificationButton( @@ -51,37 +51,13 @@ class LoginView extends GetView { Widget loginScreen(BuildContext context) { Widget ui; if (!controller.isLoggedIn) { - ui = !(GetPlatform.isAndroid || GetPlatform.isIOS) && controller.isRobot - ? recaptcha() - : SignInScreen( - providers: [ - GoogleProvider(clientId: DefaultFirebaseOptions.webClientId), - MyEmailAuthProvider(), - ], - showAuthActionSwitch: !controller.isRegistered, - showPasswordVisibilityToggle: true, - headerBuilder: LoginWidgets.headerBuilder, - subtitleBuilder: subtitleBuilder, - footerBuilder: (context, action) => footerBuilder( - controller.showReverificationButton, - LoginController.to.credential), - sideBuilder: LoginWidgets.sideBuilder, - actions: getActions(), - ); + if (!(GetPlatform.isAndroid || GetPlatform.isIOS) && controller.isRobot) { + ui = recaptcha(); + } else { + ui = const CustomSignIn(); + } } else if (controller.isAnon) { - ui = RegisterScreen( - providers: [ - MyEmailAuthProvider(), - ], - showAuthActionSwitch: !controller.isAnon, //if Anon only SignUp - showPasswordVisibilityToggle: true, - headerBuilder: LoginWidgets.headerBuilder, - subtitleBuilder: subtitleBuilder, - footerBuilder: (context, action) => footerBuilder( - controller.showReverificationButton, LoginController.to.credential), - sideBuilder: LoginWidgets.sideBuilder, - actions: getActions(), - ); + ui = const CustomSignUp(); } else { final thenTo = Get .rootDelegate.currentConfiguration!.currentPage!.parameters?['then']; @@ -92,6 +68,41 @@ class LoginView extends GetView { return ui; } + // RegisterScreen Register() { + // return RegisterScreen( + // providers: [ + // MyEmailAuthProvider(), + // ], + // showAuthActionSwitch: !controller.isAnon, //if Anon only SignUp + // showPasswordVisibilityToggle: true, + // headerBuilder: LoginWidgets.headerBuilder, + // subtitleBuilder: subtitleBuilder, + // footerBuilder: (context, action) => footerBuilder( + // controller.showReverificationButton, LoginController.to.credential), + // sideBuilder: LoginWidgets.sideBuilder, + // actions: getActions(), + // ); + // } + + // SignInScreen SignIn() { + // return SignInScreen( + // providers: [ + // GoogleProvider( + // clientId: + // clientID), + // MyEmailAuthProvider(), + // ], + // showAuthActionSwitch: !controller.isRegistered, + // showPasswordVisibilityToggle: true, + // headerBuilder: LoginWidgets.headerBuilder, + // subtitleBuilder: subtitleBuilder, + // footerBuilder: (context, action) => footerBuilder( + // controller.showReverificationButton, LoginController.to.credential), + // sideBuilder: LoginWidgets.sideBuilder, + // actions: getActions(), + // ); + // } + Widget recaptcha() { //TODO: Add Recaptcha return Scaffold( diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 7269755d..41c6b769 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:get_flutter_fire/app/modules/login/views/custom_signUp.dart'; import '../../models/access_level.dart'; import '../../models/role.dart'; @@ -60,6 +61,10 @@ class AppPages { page: () => const LoginView(), binding: LoginBinding(), ), + Screen.SIGNUP.getPage( + page: () => const CustomSignUp(), + binding: LoginBinding(), + ), Screen.REGISTER.getPage( page: () => const RegisterView(), binding: RegisterBinding(), diff --git a/lib/models/screens.dart b/lib/models/screens.dart index 24dee39f..fc66d0a5 100644 --- a/lib/models/screens.dart +++ b/lib/models/screens.dart @@ -41,6 +41,10 @@ enum Screen implements ActionEnum { icon: Icons.login, accessor_: AccessedVia.widget, accessLevel: AccessLevel.notAuthed), + SIGNUP('/signUp', + icon: Icons.login, + accessor_: AccessedVia.widget, + accessLevel: AccessLevel.notAuthed), PROFILE('/profile', icon: Icons.account_box_rounded, label: "Profile", @@ -175,3 +179,4 @@ enum Screen implements ActionEnum { Widget? widget(GetNavConfig current) => (this == LOGIN) ? LoginBottomSheetToggle(current) : null; } + diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 8bf72aaa..882befd4 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -1,10 +1,14 @@ // ignore_for_file: avoid_print +import 'dart:developer'; + +import 'package:cloud_functions/cloud_functions.dart'; 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 'package:google_sign_in/google_sign_in.dart'; import '../models/screens.dart'; import '../constants.dart'; @@ -26,13 +30,20 @@ class AuthService extends GetxService { @override onInit() { super.onInit(); - if (useEmulator) _auth.useAuthEmulator(emulatorHost, 9099); + if (useEmulator) { + _auth.useAuthEmulator(emulatorHost, 9099); + print("Using emulator. $emulatorHost"); + } _firebaseUser.bindStream(_auth.authStateChanges()); _auth.authStateChanges().listen((User? user) { if (user != null) { user.getIdTokenResult().then((token) { + print("Custom claim: ${token.claims?["role"]}"); _userRole.value = Role.fromString(token.claims?["role"]); }); + Get.rootDelegate.offNamed(Screen.HOME.route); + } else if (user == null) { + Get.rootDelegate.offNamed(Screen.LOGIN.route); } }); } @@ -52,8 +63,58 @@ class AuthService extends GetxService { ? (user!.displayName ?? user!.email) : 'Guest'; - void login() { - // this is not needed as we are using Firebase UI for the login part + final GoogleSignIn _googleSignIn = GoogleSignIn( + clientId: + clientID); + Future signInwithGoogle() async { + try { + final GoogleSignInAccount? googleSignInAccount = + await _googleSignIn.signIn(); + final GoogleSignInAuthentication googleSignInAuthentication = + await googleSignInAccount!.authentication; + final AuthCredential credential = GoogleAuthProvider.credential( + accessToken: googleSignInAuthentication.accessToken, + idToken: googleSignInAuthentication.idToken, + ); + await _auth.signInWithCredential(credential); + print('Done'); + } on FirebaseAuthException catch (e) { + print(e.message); + rethrow; + } + return null; + } + + Future login(String email, String password) async { + // isLoading.value = true; + + try { + await _auth.signInWithEmailAndPassword(email: email, password: password); + } on FirebaseAuthException catch (e) { + print(e); + String errorMessage; + + switch (e.code) { + case 'user-not-found': + errorMessage = 'No user found for that email.'; + break; + case 'wrong-password': + errorMessage = 'Wrong password provided for that user.'; + break; + case 'invalid-email': + errorMessage = 'The email address is badly formatted.'; + break; + default: + errorMessage = + 'An unknown error occurred. Please try again later. ${e.toString()}'; + } + Get.snackbar('Login Error', errorMessage); + } catch (error) { + Get.snackbar('Error', 'An unexpected error occurred. Please try again.'); + print("Error during login: ${error.toString()}"); + } finally { + // isLoading.value = false; + } } void sendVerificationMail({EmailAuthCredential? emailAuth}) async { @@ -116,6 +177,36 @@ class AuthService extends GetxService { .offAndToNamed(thenTo ?? Screen.PROFILE.route); //Profile has the forms } + Future signup(String email, String password) async { + try { + UserCredential userCredential = + await _auth.createUserWithEmailAndPassword( + email: email, + password: password, + ); + print("User created"); + HttpsCallableResult result = + await FirebaseFunctions.instance.httpsCallable('addUserRole').call({ + 'email': email, + }); + + print("Result: $result"); + + // Optionally send verification email + if (true) { + await userCredential.user!.sendEmailVerification(); + } + + registered.value = true; + // Navigate to profile or other destination + final thenTo = Get + .rootDelegate.currentConfiguration!.currentPage!.parameters?['then']; + Get.rootDelegate.offAndToNamed(thenTo ?? Screen.PROFILE.route); + } catch (e) { + Get.snackbar('Registration Error', 'Failed to register: $e'); + } + } + void logout() { _auth.signOut(); if (isAnon) _auth.currentUser?.delete(); @@ -181,6 +272,15 @@ class AuthService extends GetxService { }; }; } + + resetPassword({required String email}) { + try { + _auth.sendPasswordResetEmail(email: email); + } catch (e) { + log("Error sending reset link: $e"); + rethrow; + } + } } class MyCredential extends AuthCredential { diff --git a/pubspec.lock b/pubspec.lock index 877fc75e..38a4c2f5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,6 +49,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + cloud_functions: + dependency: "direct main" + description: + name: cloud_functions + sha256: ddec68a2fbee603527c009bb20c6bd071559dfa87fda55d9d92052d1ebff5377 + url: "https://pub.dev" + source: hosted + version: "4.7.6" + cloud_functions_platform_interface: + dependency: transitive + description: + name: cloud_functions_platform_interface + sha256: "0c6fca0e64fc2d3a3834d39f99b0ee6f76d96f94bb5acf4593af891df914d175" + url: "https://pub.dev" + source: hosted + version: "5.5.28" + cloud_functions_web: + dependency: transitive + description: + name: cloud_functions_web + sha256: af536e7c7223c64250c6cc384dc553d76bbacc9b9127389df0c654887f203911 + url: "https://pub.dev" + source: hosted + version: "4.9.6" collection: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d000e5f5..8d8124f1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,6 +24,7 @@ dependencies: firebase_ui_localizations: ^1.12.0 firebase_remote_config: ^4.4.7 firebase_analytics: ^10.10.7 + cloud_functions: ^4.7.6 dev_dependencies: flutter_lints: 3.0.2 From 0d780efd1735326ca43c07e2d4b138bc4e4ffaec Mon Sep 17 00:00:00 2001 From: Hardik Date: Mon, 15 Jul 2024 21:54:19 +0530 Subject: [PATCH 13/23] added check if the path mentioned is for bottom navigation --- lib/app/routes/screen_extension.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/app/routes/screen_extension.dart b/lib/app/routes/screen_extension.dart index e334c4e9..ca90f303 100644 --- a/lib/app/routes/screen_extension.dart +++ b/lib/app/routes/screen_extension.dart @@ -112,10 +112,9 @@ extension RoleExtension on Role { int getCurrentIndexFromRoute(GetNavConfig? currentRoute) { final String? currentLocation = currentRoute?.uri.toString(); int currentIndex = 0; - if (currentLocation != null) { + if (currentLocation != null && currentLocation.startsWith('/home')) { // removinng '/home' from the start of the location - final filteredLocation = - currentLocation.replaceFirst(RegExp(r'^/home'), ''); + final filteredLocation = currentLocation.replaceFirst('/home', ''); currentIndex = tabs.indexWhere((tab) { return filteredLocation.startsWith(tab.path); }); From 10f710ba0c30116b7a5a015ccc2c2863af16c1f6 Mon Sep 17 00:00:00 2001 From: vedantbhawnani Date: Wed, 17 Jul 2024 11:47:02 +0530 Subject: [PATCH 14/23] feature/phone verification --- assets/icons/google.png | Bin 0 -> 20865 bytes lib/app/modules/login/views/custom_login.dart | 40 +++++-- .../modules/login/views/custom_signUp.dart | 106 +++++++++++------- .../bindings/phone_auth_binding.dart | 13 +++ .../controllers/phone_auth_controller.dart | 18 +++ .../modules/phone_auth/views/phone_auth.dart | 77 +++++++++++++ lib/app/routes/app_pages.dart | 6 + lib/models/screens.dart | 5 +- lib/services/auth_service.dart | 53 ++++++++- 9 files changed, 259 insertions(+), 59 deletions(-) create mode 100644 assets/icons/google.png create mode 100644 lib/app/modules/phone_auth/bindings/phone_auth_binding.dart create mode 100644 lib/app/modules/phone_auth/controllers/phone_auth_controller.dart create mode 100644 lib/app/modules/phone_auth/views/phone_auth.dart diff --git a/assets/icons/google.png b/assets/icons/google.png new file mode 100644 index 0000000000000000000000000000000000000000..494acede0c520f847f75982ca1f671fc6eaa889e GIT binary patch literal 20865 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 G$o~QRsPyvy literal 0 HcmV?d00001 diff --git a/lib/app/modules/login/views/custom_login.dart b/lib/app/modules/login/views/custom_login.dart index d9e946ca..3184c099 100644 --- a/lib/app/modules/login/views/custom_login.dart +++ b/lib/app/modules/login/views/custom_login.dart @@ -181,18 +181,36 @@ class CustomSignIn extends StatelessWidget { SizedBox(height: height * 0.02), //google sign in - GestureDetector( - onTap: () => AuthService().signInwithGoogle(), - child: Container( - padding: EdgeInsets.all(width * 0.03), - margin: EdgeInsets.symmetric(horizontal: width * 0.08), - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () => AuthService().signInwithGoogle(), + child: Container( + padding: EdgeInsets.all(width * 0.03), + margin: EdgeInsets.symmetric(horizontal: width * 0.04), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(10), + ), + child: Image.asset('assets/icons/google.png', + height: height * 0.045), + ), ), - child: Image.asset('assets/icons/google.png', - height: height * 0.045), - ), + GestureDetector( + onTap: () => + Get.rootDelegate.toNamed(Screen.MOBILEAUTH.route), + child: Container( + padding: EdgeInsets.all(width * 0.03), + margin: EdgeInsets.symmetric(horizontal: width * 0.04), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(10), + ), + child: Icon(Icons.phone, size: height * 0.045), + ), + ), + ], ), SizedBox(height: height * 0.02), diff --git a/lib/app/modules/login/views/custom_signUp.dart b/lib/app/modules/login/views/custom_signUp.dart index 4de191ee..1b562803 100644 --- a/lib/app/modules/login/views/custom_signUp.dart +++ b/lib/app/modules/login/views/custom_signUp.dart @@ -86,8 +86,10 @@ class CustomSignUp extends GetView { } }, child: Container( - padding: EdgeInsets.all(width * 0.05), + padding: EdgeInsets.symmetric(horizontal: width * 0.05), margin: EdgeInsets.symmetric(horizontal: width * 0.1), + height: height * 0.07, + width: width * 0.2, decoration: BoxDecoration( color: Colors.black, borderRadius: BorderRadius.circular(10), @@ -103,48 +105,66 @@ class CustomSignUp extends GetView { SizedBox(height: height * 0.05), - // //or continue with - // Row( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // SizedBox( - // width: width * 0.2, - // child: Divider( - // thickness: 0.5, - // color: Colors.grey.shade900, - // )), - // SizedBox( - // width: width * 0.05, - // ), - // const Text("Or Continue with"), - // SizedBox( - // width: width * 0.05, - // ), - // SizedBox( - // width: width * 0.2, - // child: Divider( - // thickness: 0.5, - // color: Colors.grey.shade900, - // )), - // ], - // ), - - // SizedBox(height: height * 0.01), - - // //google sign in - // GestureDetector( - // onTap: () => AuthService().signInwithGoogle(), - // child: Container( - // padding: EdgeInsets.all(width * 0.03), - // margin: EdgeInsets.symmetric(horizontal: width * 0.1), - // decoration: BoxDecoration( - // color: Colors.grey.shade200, - // borderRadius: BorderRadius.circular(10), - // ), - // child: Image.asset('assets/icons/google.png', - // height: height * 0.045), - // ), - // ), + //or continue with + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: width * 0.2, + child: Divider( + thickness: 0.5, + color: Colors.grey.shade900, + )), + SizedBox( + width: width * 0.05, + ), + const Text("Or Continue with"), + SizedBox( + width: width * 0.05, + ), + SizedBox( + width: width * 0.2, + child: Divider( + thickness: 0.5, + color: Colors.grey.shade900, + )), + ], + ), + + SizedBox(height: height * 0.01), + + //google sign in + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: () => AuthService().signInwithGoogle(), + child: Container( + padding: EdgeInsets.all(width * 0.03), + margin: EdgeInsets.symmetric(horizontal: width * 0.04), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(10), + ), + child: Image.asset('assets/icons/google.png', + height: height * 0.045), + ), + ), + GestureDetector( + onTap: () => + Get.rootDelegate.toNamed(Screen.MOBILEAUTH.route), + child: Container( + padding: EdgeInsets.all(width * 0.03), + margin: EdgeInsets.symmetric(horizontal: width * 0.04), + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(10), + ), + child: Icon(Icons.phone, size: height * 0.045), + ), + ), + ], + ), SizedBox(height: height * 0.01), diff --git a/lib/app/modules/phone_auth/bindings/phone_auth_binding.dart b/lib/app/modules/phone_auth/bindings/phone_auth_binding.dart new file mode 100644 index 00000000..c3aedaaf --- /dev/null +++ b/lib/app/modules/phone_auth/bindings/phone_auth_binding.dart @@ -0,0 +1,13 @@ +import 'package:get/get.dart'; + +import '../controllers/phone_auth_controller.dart'; + + +class MobileAuthBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut( + () => MobileAuthController(), + ); + } +} diff --git a/lib/app/modules/phone_auth/controllers/phone_auth_controller.dart b/lib/app/modules/phone_auth/controllers/phone_auth_controller.dart new file mode 100644 index 00000000..b4eb4393 --- /dev/null +++ b/lib/app/modules/phone_auth/controllers/phone_auth_controller.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +// PhoneAuthController is a firebase controller name, hence that name cannot be used. +class MobileAuthController extends GetxController { + final TextEditingController phoneNumberController = TextEditingController(); + final TextEditingController otpController = TextEditingController(); + RxString verificationId = ''.obs; + RxBool codeSent = false.obs; + RxBool isLoading = false.obs; + + @override + void onClose() { + phoneNumberController.dispose(); + otpController.dispose(); + super.onClose(); + } +} diff --git a/lib/app/modules/phone_auth/views/phone_auth.dart b/lib/app/modules/phone_auth/views/phone_auth.dart new file mode 100644 index 00000000..ae59b06a --- /dev/null +++ b/lib/app/modules/phone_auth/views/phone_auth.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:get_flutter_fire/app/modules/phone_auth/controllers/phone_auth_controller.dart'; +import 'package:get_flutter_fire/services/auth_service.dart'; + +class MobileAuth extends GetView { + const MobileAuth({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Phone Authentication')), + body: Center( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Obx( + () => controller.codeSent.value + ? OtpScreen(verificationId: controller.verificationId.value) + : const VerifyPhoneScreen(), + ), + ), + ), + ); + } +} + +class VerifyPhoneScreen extends GetView { + const VerifyPhoneScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextField( + controller: controller.phoneNumberController, + keyboardType: TextInputType.phone, + decoration: const InputDecoration(hintText: 'Enter Phone Number'), + ), + const SizedBox(height: 20), + Obx(() => controller.isLoading.value + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: () => AuthService() + .verifyMobileNumber(controller.phoneNumberController.text), + child: const Text('Send OTP'), + )), + ], + ); + } +} + +class OtpScreen extends GetView { + final String verificationId; + const OtpScreen({super.key, required this.verificationId}); + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextField( + controller: controller.otpController, + keyboardType: TextInputType.number, + decoration: const InputDecoration(hintText: 'Enter OTP'), + ), + const SizedBox(height: 20), + Obx(() => controller.isLoading.value + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: () => AuthService() + .verifyOTP(controller.otpController.text, verificationId), + child: const Text('Verify OTP'), + )), + ], + ); + } +} diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 41c6b769..6cae356f 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get_flutter_fire/app/modules/login/views/custom_signUp.dart'; +import 'package:get_flutter_fire/app/modules/phone_auth/bindings/phone_auth_binding.dart'; +import 'package:get_flutter_fire/app/modules/phone_auth/views/phone_auth.dart'; import '../../models/access_level.dart'; import '../../models/role.dart'; @@ -65,6 +67,10 @@ class AppPages { page: () => const CustomSignUp(), binding: LoginBinding(), ), + Screen.MOBILEAUTH.getPage( + page: () => const MobileAuth(), + binding: MobileAuthBinding(), + ), Screen.REGISTER.getPage( page: () => const RegisterView(), binding: RegisterBinding(), diff --git a/lib/models/screens.dart b/lib/models/screens.dart index fc66d0a5..0b64d088 100644 --- a/lib/models/screens.dart +++ b/lib/models/screens.dart @@ -45,6 +45,10 @@ enum Screen implements ActionEnum { icon: Icons.login, accessor_: AccessedVia.widget, accessLevel: AccessLevel.notAuthed), + MOBILEAUTH('/mobileAuth', + icon: Icons.login, + accessor_: AccessedVia.widget, + accessLevel: AccessLevel.notAuthed), PROFILE('/profile', icon: Icons.account_box_rounded, label: "Profile", @@ -179,4 +183,3 @@ enum Screen implements ActionEnum { Widget? widget(GetNavConfig current) => (this == LOGIN) ? LoginBottomSheetToggle(current) : null; } - diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index dfa2a862..c2cac70a 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -8,6 +8,7 @@ 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 'package:get_flutter_fire/app/modules/phone_auth/controllers/phone_auth_controller.dart'; import 'package:google_sign_in/google_sign_in.dart'; import '../models/screens.dart'; @@ -32,13 +33,11 @@ class AuthService extends GetxService { super.onInit(); if (useEmulator) { _auth.useAuthEmulator(emulatorHost, 9099); - print("Using emulator. $emulatorHost"); } _firebaseUser.bindStream(_auth.authStateChanges()); _auth.authStateChanges().listen((User? user) { if (user != null) { user.getIdTokenResult().then((token) { - print("Custom claim: ${token.claims?["role"]}"); _userRole.value = Role.fromString(token.claims?["role"]); }); Get.rootDelegate.offNamed(Screen.HOME.route); @@ -63,6 +62,8 @@ class AuthService extends GetxService { ? (user!.displayName ?? user!.email) : 'Guest'; +// Function to handle google sign in. +//* Can use silent sign in to make the flow smoother on the web. final GoogleSignIn _googleSignIn = GoogleSignIn(clientId: const String.fromEnvironment('CLIENT_ID')); Future signInwithGoogle() async { @@ -76,7 +77,6 @@ class AuthService extends GetxService { idToken: googleSignInAuthentication.idToken, ); await _auth.signInWithCredential(credential); - print('Done'); } on FirebaseAuthException catch (e) { print(e.message); rethrow; @@ -84,9 +84,54 @@ class AuthService extends GetxService { return null; } + // Functions to handle phone authentication. + // Function to verify the phone number. On android this tries to read the code directly without the user having to manually enter the code. + Future verifyMobileNumber(String phoneNumber) async { + print("HEre"); + await _auth.verifyPhoneNumber( + phoneNumber: phoneNumber, + verificationCompleted: (PhoneAuthCredential credential) async { + await _auth.signInWithCredential(credential); + }, + verificationFailed: (FirebaseAuthException e) { + String errorMessage = 'Verification failed'; + switch (e.code) { + case 'invalid-verification-code': + errorMessage = 'Invalid SMS code.'; + break; + case 'expired-verification-code': + errorMessage = 'SMS code has expired.'; + break; + default: + errorMessage = 'An unknown error occurred. Please try again later.'; + } + Get.snackbar(errorMessage, ''); + }, + codeSent: (String verificationId, int? resendToken) { + print("Code sent"); + Get.find().codeSent.value = true; + Get.find().verificationId.value = verificationId; + }, + codeAutoRetrievalTimeout: (String verificationId) {}, + timeout: const Duration(seconds: 60), + ); + } + + // Verify the OTP. + Future verifyOTP(String smsCode, String verificationId) async { + try { + print("here"); + PhoneAuthCredential credential = PhoneAuthProvider.credential( + verificationId: verificationId, smsCode: smsCode); + await _auth.signInWithCredential(credential); + print("Done"); + } catch (e) { + print(e.toString()); + } + } + Future login(String email, String password) async { // isLoading.value = true; - try { await _auth.signInWithEmailAndPassword(email: email, password: password); } on FirebaseAuthException catch (e) { From 1180864430117bf79d40a77fd92c441308c37639 Mon Sep 17 00:00:00 2001 From: Hardik Date: Wed, 17 Jul 2024 11:50:36 +0530 Subject: [PATCH 15/23] using full path for bottom navigation --- lib/app/routes/screen_extension.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/app/routes/screen_extension.dart b/lib/app/routes/screen_extension.dart index ca90f303..23877c7d 100644 --- a/lib/app/routes/screen_extension.dart +++ b/lib/app/routes/screen_extension.dart @@ -110,13 +110,13 @@ extension ScreenExtension on Screen { extension RoleExtension on Role { int getCurrentIndexFromRoute(GetNavConfig? currentRoute) { - final String? currentLocation = currentRoute?.uri.toString(); + final String? currentLocation = currentRoute?.uri.path; int currentIndex = 0; - if (currentLocation != null && currentLocation.startsWith('/home')) { - // removinng '/home' from the start of the location - final filteredLocation = currentLocation.replaceFirst('/home', ''); + if (currentLocation != null) { currentIndex = tabs.indexWhere((tab) { - return filteredLocation.startsWith(tab.path); + String parentPath = tab.parent?.path ?? ''; + String fullPath = '$parentPath${tab.path}'; + return currentLocation.startsWith(fullPath); }); } return (currentIndex > 0) ? currentIndex : 0; From 6d64d126e1b6f0f473d724f055c62b0b5e1c0389 Mon Sep 17 00:00:00 2001 From: vedantbhawnani Date: Thu, 18 Jul 2024 01:32:36 +0530 Subject: [PATCH 16/23] update/phone auth screens UI --- README.md | 2 +- .../modules/phone_auth/views/phone_auth.dart | 146 +++++++++++++----- lib/services/auth_service.dart | 2 - 3 files changed, 112 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index be46f067..e937aa70 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Step 7: Additional Auth flow items * 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] +4. Added 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 diff --git a/lib/app/modules/phone_auth/views/phone_auth.dart b/lib/app/modules/phone_auth/views/phone_auth.dart index ae59b06a..8ba8d991 100644 --- a/lib/app/modules/phone_auth/views/phone_auth.dart +++ b/lib/app/modules/phone_auth/views/phone_auth.dart @@ -9,7 +9,10 @@ class MobileAuth extends GetView { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Phone Authentication')), + appBar: AppBar( + title: const Text('Phone Authentication'), + centerTitle: true, + ), body: Center( child: Padding( padding: const EdgeInsets.all(20.0), @@ -29,49 +32,122 @@ class VerifyPhoneScreen extends GetView { @override Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextField( - controller: controller.phoneNumberController, - keyboardType: TextInputType.phone, - decoration: const InputDecoration(hintText: 'Enter Phone Number'), - ), - const SizedBox(height: 20), - Obx(() => controller.isLoading.value - ? const CircularProgressIndicator() - : ElevatedButton( - onPressed: () => AuthService() - .verifyMobileNumber(controller.phoneNumberController.text), - child: const Text('Send OTP'), - )), - ], - ); + return Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 500), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TextField( + controller: controller.phoneNumberController, + keyboardType: TextInputType.phone, + decoration: InputDecoration( + hintText: 'Enter Phone Number', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + prefixIcon: const Icon(Icons.phone), + ), + ), + const SizedBox(height: 20), + Obx(() => controller.isLoading.value + ? const Center(child: CircularProgressIndicator()) + : ElevatedButton( + onPressed: () => AuthService().verifyMobileNumber( + controller.phoneNumberController.text), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: const Text( + 'Send OTP', + style: TextStyle(fontSize: 16), + ), + )), + ], + ), + ))); + + // return Column( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // TextField( + // controller: controller.phoneNumberController, + // keyboardType: TextInputType.phone, + // decoration: const InputDecoration(hintText: 'Enter Phone Number'), + // ), + // const SizedBox(height: 20), + // Obx(() => controller.isLoading.value + // ? const CircularProgressIndicator() + // : ElevatedButton( + // onPressed: () => AuthService() + // .verifyMobileNumber(controller.phoneNumberController.text), + // child: const Text('Send OTP'), + // )), + // ], + // ); } } class OtpScreen extends GetView { final String verificationId; const OtpScreen({super.key, required this.verificationId}); + @override Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextField( - controller: controller.otpController, - keyboardType: TextInputType.number, - decoration: const InputDecoration(hintText: 'Enter OTP'), + return Scaffold( + // appBar: AppBar( + // title: const Text('Verify OTP'), + // centerTitle: true, + // ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Enter the OTP sent to your mobile number', + style: TextStyle(fontSize: 18), + textAlign: TextAlign.center, + ), + const SizedBox(height: 20), + TextField( + controller: controller.otpController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintText: 'Enter OTP', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + contentPadding: + const EdgeInsets.symmetric(vertical: 15, horizontal: 10), + ), + ), + const SizedBox(height: 20), + Obx(() => controller.isLoading.value + ? const CircularProgressIndicator() + : SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () => AuthService().verifyOTP( + controller.otpController.text, verificationId), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 15), + textStyle: const TextStyle(fontSize: 16), + ), + child: const Text('Verify OTP'), + ), + )), + ], + ), ), - const SizedBox(height: 20), - Obx(() => controller.isLoading.value - ? const CircularProgressIndicator() - : ElevatedButton( - onPressed: () => AuthService() - .verifyOTP(controller.otpController.text, verificationId), - child: const Text('Verify OTP'), - )), - ], + ), ); } } diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index c2cac70a..cf74213d 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -87,7 +87,6 @@ class AuthService extends GetxService { // Functions to handle phone authentication. // Function to verify the phone number. On android this tries to read the code directly without the user having to manually enter the code. Future verifyMobileNumber(String phoneNumber) async { - print("HEre"); await _auth.verifyPhoneNumber( phoneNumber: phoneNumber, verificationCompleted: (PhoneAuthCredential credential) async { @@ -120,7 +119,6 @@ class AuthService extends GetxService { // Verify the OTP. Future verifyOTP(String smsCode, String verificationId) async { try { - print("here"); PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId, smsCode: smsCode); await _auth.signInWithCredential(credential); From b99f3fdd48934da5b8ddf78823e97e7ed7770bb0 Mon Sep 17 00:00:00 2001 From: Aastha Gadhvi Date: Fri, 19 Jul 2024 11:21:12 +0530 Subject: [PATCH 17/23] Added Search Bar (Toggle Button for phones) on Top Center with Title --- devtools_options.yaml | 3 + .../controllers/dashboard_controller.dart | 5 + .../dashboard/views/dashboard_view.dart | 137 +++++++++++++-- .../login/controllers/login_controller.dart | 51 +++++- lib/app/modules/login/views/login_view.dart | 56 +++++++ .../login/views/phone_verification_view.dart | 53 ++++++ .../controllers/profile_controller.dart | 91 ++++++++++ .../modules/profile/views/profile_view.dart | 158 ++++++++++++++++++ lib/services/auth_service.dart | 3 + lib/services/phone_auth_screen.dart | 111 ++++++++++++ pubspec.lock | 16 ++ pubspec.yaml | 1 + 12 files changed, 673 insertions(+), 12 deletions(-) create mode 100644 devtools_options.yaml create mode 100644 lib/app/modules/login/views/phone_verification_view.dart create mode 100644 lib/services/phone_auth_screen.dart diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 00000000..fa0b357c --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/lib/app/modules/dashboard/controllers/dashboard_controller.dart b/lib/app/modules/dashboard/controllers/dashboard_controller.dart index 24d91a16..4732b7b6 100644 --- a/lib/app/modules/dashboard/controllers/dashboard_controller.dart +++ b/lib/app/modules/dashboard/controllers/dashboard_controller.dart @@ -14,4 +14,9 @@ class DashboardController extends GetxController { }, ); } + var isSearchBarVisible = true.obs; + void toggleSearchBarVisibility() { + isSearchBarVisible.value = !isSearchBarVisible.value; + } + // Observable state for current time (example) } diff --git a/lib/app/modules/dashboard/views/dashboard_view.dart b/lib/app/modules/dashboard/views/dashboard_view.dart index f475030f..648f164a 100644 --- a/lib/app/modules/dashboard/views/dashboard_view.dart +++ b/lib/app/modules/dashboard/views/dashboard_view.dart @@ -1,6 +1,36 @@ +// 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 'package:firebase_remote_config/firebase_remote_config.dart'; +import '../../../../services/remote_config.dart'; import '../controllers/dashboard_controller.dart'; class DashboardView extends GetView { @@ -9,20 +39,105 @@ class DashboardView extends GetView { @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()}'), - ], + appBar: AppBar( + title: const Text('Dashboard'), + centerTitle: true, + actions: [ + GetBuilder( + builder: (controller) { + return FutureBuilder( + future: RemoteConfig.instance.then((config) => config.showSearchBarOnTop()), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError || !snapshot.data!) { + return const SizedBox.shrink(); + } else { + return GetPlatform.isMobile + ? PopupMenuButton( + onSelected: (value) { + if (value == 'toggleSearchBar') { + controller.toggleSearchBarVisibility(); + } + }, + itemBuilder: (BuildContext context) { + return [ + PopupMenuItem( + value: 'toggleSearchBar', + child: Row( + children: [ + const Icon(Icons.search), + const SizedBox(width: 8), + const Text('Toggle Search Bar'), + ], + ), + ), + ]; + }, + ) + : const SizedBox.shrink(); + } + }, + ); + }, ), + ], + ), + body: Obx( + () { + // Use the controller's state for search bar visibility + bool isSearchBarVisible = controller.isSearchBarVisible.value; + + return FutureBuilder( + future: RemoteConfig.instance.then((config) => config.showSearchBarOnTop()), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } else { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (isSearchBarVisible) + Padding( + padding: const EdgeInsets.all(8.0), + child: _buildSearchBar(), + ), + Expanded( + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'DashboardView is working', + style: TextStyle(fontSize: 20), + ), + Text('Time: ${controller.now.value.toString()}'), + ], + ), + ), + ), + ], + ); + } + }, + ); + }, + ), + ); + } + + Widget _buildSearchBar() { + return TextField( + decoration: InputDecoration( + hintText: 'Search...', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), ), + prefixIcon: Icon(Icons.search), ), ); } } + diff --git a/lib/app/modules/login/controllers/login_controller.dart b/lib/app/modules/login/controllers/login_controller.dart index 5178fec9..ce2df429 100644 --- a/lib/app/modules/login/controllers/login_controller.dart +++ b/lib/app/modules/login/controllers/login_controller.dart @@ -1,11 +1,59 @@ +// // 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:firebase_auth/firebase_auth.dart' as fba; +// 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); +// final Rx verificationId = ''.obs; +// final Rxn credential = Rxn(); +// final Rx isPhoneVerified = false.obs; +// +// 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:firebase_auth/firebase_auth.dart' as fba; +import 'package:firebase_auth/firebase_auth.dart'; 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); + final Rx verificationId = ''.obs; + final Rxn credential = + Rxn(); + final Rx isPhoneVerified = false.obs; // New observable bool get isRobot => AuthService.to.robot.value == true; @@ -17,4 +65,5 @@ class LoginController extends GetxController { 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..ce0ea586 100644 --- a/lib/app/modules/login/views/login_view.dart +++ b/lib/app/modules/login/views/login_view.dart @@ -16,6 +16,7 @@ class LoginView extends GetView { bool show, fba.EmailAuthCredential? credential) { // Below is very important. // See [https://stackoverflow.com/questions/69351845/this-obx-widget-cannot-be-marked-as-needing-to-build-because-the-framework-is-al] + WidgetsBinding.instance.addPostFrameCallback((_) { controller.showReverificationButton.value = show; }); @@ -149,6 +150,61 @@ class EmailLinkButton extends StatelessWidget { }); @override + // Widget loginScreen(BuildContext context) { + // Widget ui; + // bool showPhoneVerification = controller.showReverificationButton.value; + // + // if (!controller.isLoggedIn) { + // ui = !(GetPlatform.isAndroid || GetPlatform.isIOS) && controller.isRobot + // ? recaptcha() + // : SignInScreen( + // providers: [ + // GoogleProvider(clientId: DefaultFirebaseOptions.webClientId), + // MyEmailAuthProvider(), + // ], + // showAuthActionSwitch: !controller.isRegistered, + // showPasswordVisibilityToggle: true, + // headerBuilder: LoginWidgets.headerBuilder, + // subtitleBuilder: subtitleBuilder, + // footerBuilder: (context, action) => footerBuilder( + // controller.showReverificationButton, + // LoginController.to.credential), + // sideBuilder: LoginWidgets.sideBuilder, + // actions: getActions(), + // ); + // } else if (controller.isAnon) { + // ui = RegisterScreen( + // providers: [ + // MyEmailAuthProvider(), + // ], + // showAuthActionSwitch: !controller.isAnon, //if Anon only SignUp + // showPasswordVisibilityToggle: true, + // headerBuilder: LoginWidgets.headerBuilder, + // subtitleBuilder: subtitleBuilder, + // footerBuilder: (context, action) => footerBuilder( + // controller.showReverificationButton, LoginController.to.credential), + // sideBuilder: LoginWidgets.sideBuilder, + // actions: getActions(), + // ); + // } else { + // final thenTo = Get + // .rootDelegate.currentConfiguration!.currentPage!.parameters?['then']; + // Get.rootDelegate.offNamed(thenTo ?? + // (controller.isRegistered ? Screen.HOME : Screen.REGISTER).route); + // ui = const Scaffold(); + // } + // + // // Add phone verification UI below the existing UI components + // return Column( + // crossAxisAlignment: CrossAxisAlignment.stretch, + // children: [ + // ui, // Existing UI + // if (showPhoneVerification) + // phoneVerificationUI(context), + // ], + // ); + // } + Widget build(BuildContext context) { return Obx(() => Visibility( visible: show.value, diff --git a/lib/app/modules/login/views/phone_verification_view.dart b/lib/app/modules/login/views/phone_verification_view.dart new file mode 100644 index 00000000..960f3362 --- /dev/null +++ b/lib/app/modules/login/views/phone_verification_view.dart @@ -0,0 +1,53 @@ +// import 'package:flutter/material.dart'; +// import 'package:get/get.dart'; +// import '../controllers/login_controller.dart'; +// +// class PhoneVerificationView extends StatelessWidget { +// final TextEditingController phoneController = TextEditingController(); +// final TextEditingController codeController = TextEditingController(); +// +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// appBar: AppBar( +// title: Text('Phone Verification'), +// ), +// body: Padding( +// padding: const EdgeInsets.all(16.0), +// child: Column( +// children: [ +// TextField( +// controller: phoneController, +// decoration: InputDecoration(labelText: 'Phone Number'), +// ), +// ElevatedButton( +// onPressed: () { +// LoginController.to.verifyPhoneNumber( +// phoneController.text, +// (credential) { +// // Handle verification completed +// Get.snackbar('Success', 'Phone number verified'); +// }, +// ); +// }, +// child: Text('Verify Phone Number'), +// ), +// TextField( +// controller: codeController, +// decoration: InputDecoration(labelText: 'Verification Code'), +// ), +// ElevatedButton( +// onPressed: () { +// LoginController.to.signInWithPhoneNumber( +// LoginController.to.verificationId.value, +// codeController.text, +// ); +// }, +// child: Text('Sign In'), +// ), +// ], +// ), +// ), +// ); +// } +// } diff --git a/lib/app/modules/profile/controllers/profile_controller.dart b/lib/app/modules/profile/controllers/profile_controller.dart index 0c1e059e..f09baa3a 100644 --- a/lib/app/modules/profile/controllers/profile_controller.dart +++ b/lib/app/modules/profile/controllers/profile_controller.dart @@ -60,3 +60,94 @@ class ProfileController extends GetxController { 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:flutter/material.dart'; +// import 'package:get/get.dart'; +// import 'package:get_storage/get_storage.dart'; +// import 'package:path/path.dart'; +// import '../../../../services/auth_service.dart'; +// +// // Define the Persona class +// class Persona { +// final String name; +// final String imagePath; +// final bool isDarkTheme; +// +// Persona({required this.name, required this.imagePath, required this.isDarkTheme}); +// } +// +// // List of personas +// final List personas = [ +// Persona(name: 'Default', imagePath: 'assets/persona/default.png', isDarkTheme: false), +// Persona(name: 'Kids', imagePath: 'assets/persona/kids.png', isDarkTheme: false), +// Persona(name: 'Dark', imagePath: 'assets/persona/dark.png', isDarkTheme: true), +// ]; +// +// class ProfileController extends GetxController { +// FirebaseStorage storage = FirebaseStorage.instance; +// User? currentUser = AuthService.to.user; +// final Rxn _photoURL = Rxn(); +// final RxString selectedPersona = 'Default'.obs; +// +// File? _photo; +// +// String? get photoURL => _photoURL.value; +// +// @override +// void onInit() { +// super.onInit(); +// _photoURL.value = currentUser!.photoURL; +// _photoURL.bindStream(currentUser!.photoURL.obs.stream); +// selectedPersona.value = GetStorage().read('selectedPersona') ?? 'Default'; +// } +// +// 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; +// } +// +// 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'); +// } +// +// void logout() { +// AuthService.to.logout(); +// } +// +// void updatePersona(String persona) { +// selectedPersona.value = persona; +// GetStorage().write('selectedPersona', persona); +// applyPersonaSettings(persona); +// } +// +// void applyPersonaSettings(String persona) { +// final selected = personas.firstWhere((p) => p.name == persona); +// Get.changeTheme(selected.isDarkTheme ? ThemeData.dark() : ThemeData.light()); +// // Add any other persona-specific settings here +// } +// } diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index cd9b8e28..7b834176 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -123,3 +123,161 @@ class ProfileView extends GetView { onConfirm: dlg.onSubmit); } } + +// 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 '../../../../models/screens.dart'; +// import '../../../utils/img_constants.dart'; +// import '../../../widgets/change_password_dialog.dart'; +// import '../../../widgets/image_picker_button.dart'; +// import '../controllers/profile_controller.dart'; +// +// class ProfileView extends GetView { +// const ProfileView({super.key}); +// ShapeBorder get shape => const CircleBorder(); +// double get size => 120; +// Color get placeholderColor => Colors.grey; +// +// Widget _imageFrameBuilder( +// BuildContext context, +// Widget? child, +// int? frame, +// bool? _, +// ) { +// if (frame == null) { +// return Container(color: placeholderColor); +// } +// +// return child!; +// } +// +// @override +// Widget build(BuildContext context) { +// return Obx(() => profileScreen()); +// } +// +// Widget profileScreen() { +// return AuthService.to.isLoggedInValue +// ? ProfileScreen( +// avatar: SizedBox( +// 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( +// ImgConstants.dash, +// width: size, +// fit: BoxFit.contain, +// ), +// ), +// ), +// ), +// actions: [ +// SignedOutAction((context) { +// Get.back(); +// controller.logout(); +// Get.rootDelegate.toNamed(Screen.PROFILE.route); +// }), +// AccountDeletedAction((context, user) { +// Get.defaultDialog( +// title: 'Deleted Account of ${user.displayName}', +// barrierDismissible: true, +// navigatorKey: Get.nestedKey(Screen.HOME.route), +// ); +// }) +// ], +// children: [ +// 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) { +// String? dest = await controller.uploadFile(path); +// if (dest != null) { +// await controller.updatePhotoURL(dest); +// } +// } +// }), +// const Divider(), +// Padding( +// padding: const EdgeInsets.all(8.0), +// child: Text('Select Persona:', style: TextStyle(fontSize: 18)), +// ), +// Expanded( +// child: PersonaSelection( +// personas: personas, +// onPersonaSelected: (persona) { +// controller.updatePersona(persona); +// }, +// ), +// ), +// ], +// ) +// : const Scaffold(); +// } +// +// void callChangePwdDialog() { +// var dlg = ChangePasswordDialog(controller.currentUser!); +// Get.defaultDialog( +// title: "Change Password", +// content: dlg, +// textConfirm: "Submit", +// textCancel: "Cancel", +// onConfirm: dlg.onSubmit); +// } +// } +// +// class PersonaSelection extends StatelessWidget { +// final List personas; +// final ValueChanged onPersonaSelected; +// +// PersonaSelection({required this.personas, required this.onPersonaSelected}); +// +// @override +// Widget build(BuildContext context) { +// return GridView.builder( +// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( +// crossAxisCount: 2, +// childAspectRatio: 1, +// ), +// itemCount: personas.length, +// itemBuilder: (context, index) { +// final persona = personas[index]; +// return GestureDetector( +// onTap: () { +// onPersonaSelected(persona.name); +// Get.snackbar('Persona Selected', '${persona.name} persona applied!'); +// }, +// child: Card( +// child: Column( +// children: [ +// Image.asset(persona.imagePath, height: 100, width: 100), +// Text(persona.name), +// ], +// ), +// ), +// ); +// }, +// ); +// } +// } diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 8bf72aaa..832b7c85 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -181,6 +181,8 @@ class AuthService extends GetxService { }; }; } + + //void verifyPhoneNumber(String text, Null Function(dynamic credential) param1) {} } class MyCredential extends AuthCredential { @@ -199,3 +201,4 @@ parseEmail(String message) { int j = message.indexOf('"', i); return message.substring(i, j - 1); } + diff --git a/lib/services/phone_auth_screen.dart b/lib/services/phone_auth_screen.dart new file mode 100644 index 00000000..d2c34f59 --- /dev/null +++ b/lib/services/phone_auth_screen.dart @@ -0,0 +1,111 @@ +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/material.dart'; + +class PhoneAuthScreen extends StatefulWidget { + @override + _PhoneAuthScreenState createState() => _PhoneAuthScreenState(); +} + +class _PhoneAuthScreenState extends State { + late String _verificationId; + late TextEditingController _phoneNumberController; + late TextEditingController _smsController; + + @override + void initState() { + super.initState(); + _phoneNumberController = TextEditingController(); + _smsController = TextEditingController(); + } + + @override + void dispose() { + _phoneNumberController.dispose(); + _smsController.dispose(); + super.dispose(); + } + + Future _verifyPhoneNumber() async { + await FirebaseAuth.instance.verifyPhoneNumber( + phoneNumber: '+91${_phoneNumberController.text}', + verificationCompleted: (PhoneAuthCredential credential) async { + // Auto-retrieve the SMS code and sign in + await FirebaseAuth.instance.signInWithCredential(credential); + // Navigate to your desired screen after authentication + }, + verificationFailed: (FirebaseAuthException e) { + // Handle verification failed + print(e.message); + }, + codeSent: (String verificationId, int? resendToken) { + setState(() { + _verificationId = verificationId; + }); + }, + codeAutoRetrievalTimeout: (String verificationId) { + setState(() { + _verificationId = verificationId; + }); + }, + ); + } + + void _signInWithPhoneNumber() async { + try { + final credential = PhoneAuthProvider.credential( + verificationId: _verificationId, + smsCode: _smsController.text, + ); + await FirebaseAuth.instance.signInWithCredential(credential); + // Navigate to your desired screen after authentication + } catch (e) { + print(e.toString()); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Phone Authentication'), + ), + body: Padding( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TextField( + controller: _phoneNumberController, + decoration: InputDecoration(labelText: 'Enter phone number'), + keyboardType: TextInputType.phone, + ), + SizedBox(height: 16.0), + ElevatedButton( + onPressed: _verifyPhoneNumber, + child: Text('Verify Phone Number'), + ), + SizedBox(height: 16.0), + Visibility( + visible: _verificationId != null, + child: Column( + children: [ + TextField( + controller: _smsController, + decoration: InputDecoration(labelText: 'Enter SMS Code'), + keyboardType: TextInputType.number, + ), + SizedBox(height: 16.0), + ElevatedButton( + onPressed: _signInWithPhoneNumber, + child: Text('Sign In with SMS Code'), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 877fc75e..886c9f62 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -597,6 +597,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: "direct main" description: @@ -685,6 +693,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index d000e5f5..bf263fec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ dependencies: get: 4.6.6 flutter: sdk: flutter + provider: ^6.1.2 firebase_core: ^2.31.0 firebase_ui_auth: ^1.14.0 firebase_auth: ^4.19.5 From 134d8a4d0a8a54c3d857c833c20dc769e913123f Mon Sep 17 00:00:00 2001 From: neminsheth <102215781+neminsheth@users.noreply.github.com> Date: Fri, 19 Jul 2024 18:16:55 +0530 Subject: [PATCH 18/23] Removed firebase.json I had already added firebase.json to .gitignore, but I'm not sure how it got committed. Have removed it now. --- firebase.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 firebase.json diff --git a/firebase.json b/firebase.json deleted file mode 100644 index 6643fe7b..00000000 --- a/firebase.json +++ /dev/null @@ -1 +0,0 @@ -{"flutter":{"platforms":{"dart":{"lib/firebase_options.dart":{"projectId":"sharekhan-nemin","configurations":{"android":"1:56053565487:android:f0e57a6359c84f97cb5eda","ios":"1:56053565487:ios:3515d315addadb07cb5eda","macos":"1:56053565487:ios:3515d315addadb07cb5eda","web":"1:56053565487:web:bdde9b35d35b497ccb5eda","windows":"1:56053565487:web:5c35ec65002974a6cb5eda"}}},"ios":{"default":{"projectId":"sharekhan-nemin","appId":"1:56053565487:ios:3515d315addadb07cb5eda","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"android":{"default":{"projectId":"sharekhan-nemin","appId":"1:56053565487:android:f0e57a6359c84f97cb5eda","fileOutput":"android/app/google-services.json"}},"macos":{"default":{"projectId":"sharekhan-nemin","appId":"1:56053565487:ios:3515d315addadb07cb5eda","uploadDebugSymbols":false,"fileOutput":"macos/Runner/GoogleService-Info.plist"}}}}} \ No newline at end of file From 1dee2ce5cbb0f2d1eaac004df4b1ba101784d725 Mon Sep 17 00:00:00 2001 From: Anshuman Das Date: Sat, 20 Jul 2024 12:00:32 +0530 Subject: [PATCH 19/23] fixed async bug --- lib/app/widgets/remotely_config_obx.dart | 13 ------------- lib/app/widgets/screen_widget.dart | 13 ++++++------- lib/models/screens.dart | 2 +- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/lib/app/widgets/remotely_config_obx.dart b/lib/app/widgets/remotely_config_obx.dart index a1ea63db..684503c0 100644 --- a/lib/app/widgets/remotely_config_obx.dart +++ b/lib/app/widgets/remotely_config_obx.dart @@ -8,8 +8,6 @@ class RemoteConfigController extends GetxController { final Rx values; } -/// final _name = "GetX".obs; -/// Obx(() => Text( _name.value )),... ; class RemotelyConfigObx>> extends ObxWidget { final Widget Function() builder; @@ -34,17 +32,6 @@ class RemotelyConfigObx>> Widget build() => builder(); } -/// Similar to Obx, but manages a local state. -/// Pass the initial data in constructor. -/// Useful for simple local states, like toggles, visibility, themes, -/// button states, etc. -/// Sample: -/// ObxValue((data) => Switch( -/// value: data.value, -/// onChanged: (flag) => data.value = flag, -/// ), -/// false.obs, -/// ), class RemotelyConfigObxVal extends ObxWidget { final Widget Function(T) builder; final T data; diff --git a/lib/app/widgets/screen_widget.dart b/lib/app/widgets/screen_widget.dart index edb4ead1..438f91e5 100644 --- a/lib/app/widgets/screen_widget.dart +++ b/lib/app/widgets/screen_widget.dart @@ -93,13 +93,12 @@ extension ScreenWidgetExtension on Screen { //This could be used to add icon buttons in expanded web view instead of the context menu static List topRightMenuButtons(GetNavConfig current) { List widgets = []; - Screen.topRightMenu().then((v) { - for (var screen in v) { - widgets.add(Container( - margin: const EdgeInsets.only(right: 15), - child: screen.widget(current))); - } - }); + for (var screen in Screen.topRightMenu()) { + widgets.add(Container( + margin: const EdgeInsets.only(right: 15), + child: screen.widget(current))); + } + return widgets; //This will return empty. We need a Obx } } diff --git a/lib/models/screens.dart b/lib/models/screens.dart index eb89b5a5..585f29f5 100644 --- a/lib/models/screens.dart +++ b/lib/models/screens.dart @@ -184,7 +184,7 @@ enum Screen implements ActionEnum { return list; } - static Future> topRightMenu() async { + static Iterable topRightMenu() { return Screen.values.where((Screen screen) => screen.accessor_ == AccessedVia.topRight && AuthService.to.accessLevel.index >= screen.accessLevel.index); From 170bedbdda9d5904c07d32546a87d30a7c533c1c Mon Sep 17 00:00:00 2001 From: Anshuman Das Date: Sat, 20 Jul 2024 12:29:35 +0530 Subject: [PATCH 20/23] Revert "Bugs, ToDo 13.3" --- README.md | 2 +- devtools_options.yaml | 3 - ios/Flutter/Generated.xcconfig | 14 -- ios/Flutter/flutter_export_environment.sh | 13 -- ios/Runner/GeneratedPluginRegistrant.h | 19 --- ios/Runner/GeneratedPluginRegistrant.m | 91 ---------- .../controllers/dashboard_controller.dart | 5 - .../dashboard/views/dashboard_view.dart | 137 ++------------- .../login/controllers/login_controller.dart | 51 +----- lib/app/modules/login/views/login_view.dart | 56 ------- .../login/views/phone_verification_view.dart | 53 ------ .../controllers/profile_controller.dart | 91 ---------- .../modules/profile/views/profile_view.dart | 158 ------------------ lib/services/auth_service.dart | 3 - lib/services/phone_auth_screen.dart | 111 ------------ .../ephemeral/Flutter-Generated.xcconfig | 11 -- .../ephemeral/flutter_export_environment.sh | 12 -- pubspec.lock | 16 -- pubspec.yaml | 1 - 19 files changed, 13 insertions(+), 834 deletions(-) delete mode 100644 devtools_options.yaml delete mode 100644 ios/Flutter/Generated.xcconfig delete mode 100644 ios/Flutter/flutter_export_environment.sh delete mode 100644 ios/Runner/GeneratedPluginRegistrant.h delete mode 100644 ios/Runner/GeneratedPluginRegistrant.m delete mode 100644 lib/app/modules/login/views/phone_verification_view.dart delete mode 100644 lib/services/phone_auth_screen.dart delete mode 100644 macos/Flutter/ephemeral/Flutter-Generated.xcconfig delete mode 100644 macos/Flutter/ephemeral/flutter_export_environment.sh diff --git a/README.md b/README.md index 7d403519..be46f067 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Step 5: Add Guest User/Anonymous login with a Cart and Checkout use case [https: * delete unlinked anonymous user post logout -Step 6: Add ImagePicker and Firebase Storage for profile image (Done) +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 diff --git a/devtools_options.yaml b/devtools_options.yaml deleted file mode 100644 index fa0b357c..00000000 --- a/devtools_options.yaml +++ /dev/null @@ -1,3 +0,0 @@ -description: This file stores settings for Dart & Flutter DevTools. -documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states -extensions: diff --git a/ios/Flutter/Generated.xcconfig b/ios/Flutter/Generated.xcconfig deleted file mode 100644 index ebe7b0ca..00000000 --- a/ios/Flutter/Generated.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// This is a generated file; do not edit or check into version control. -FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter -FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire -COCOAPODS_PARALLEL_CODE_SIGN=true -FLUTTER_TARGET=lib\main.dart -FLUTTER_BUILD_DIR=build -FLUTTER_BUILD_NAME=1.0.0 -FLUTTER_BUILD_NUMBER=1 -EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 -EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 -DART_OBFUSCATION=false -TRACK_WIDGET_CREATION=true -TREE_SHAKE_ICONS=false -PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh deleted file mode 100644 index e9e43111..00000000 --- a/ios/Flutter/flutter_export_environment.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter" -export "FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire" -export "COCOAPODS_PARALLEL_CODE_SIGN=true" -export "FLUTTER_TARGET=lib\main.dart" -export "FLUTTER_BUILD_DIR=build" -export "FLUTTER_BUILD_NAME=1.0.0" -export "FLUTTER_BUILD_NUMBER=1" -export "DART_OBFUSCATION=false" -export "TRACK_WIDGET_CREATION=true" -export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/ios/Runner/GeneratedPluginRegistrant.h b/ios/Runner/GeneratedPluginRegistrant.h deleted file mode 100644 index 7a890927..00000000 --- a/ios/Runner/GeneratedPluginRegistrant.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GeneratedPluginRegistrant_h -#define GeneratedPluginRegistrant_h - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface GeneratedPluginRegistrant : NSObject -+ (void)registerWithRegistry:(NSObject*)registry; -@end - -NS_ASSUME_NONNULL_END -#endif /* GeneratedPluginRegistrant_h */ diff --git a/ios/Runner/GeneratedPluginRegistrant.m b/ios/Runner/GeneratedPluginRegistrant.m deleted file mode 100644 index 11a184c0..00000000 --- a/ios/Runner/GeneratedPluginRegistrant.m +++ /dev/null @@ -1,91 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#import "GeneratedPluginRegistrant.h" - -#if __has_include() -#import -#else -@import desktop_webview_auth; -#endif - -#if __has_include() -#import -#else -@import file_picker; -#endif - -#if __has_include() -#import -#else -@import firebase_analytics; -#endif - -#if __has_include() -#import -#else -@import firebase_auth; -#endif - -#if __has_include() -#import -#else -@import firebase_core; -#endif - -#if __has_include() -#import -#else -@import firebase_dynamic_links; -#endif - -#if __has_include() -#import -#else -@import firebase_remote_config; -#endif - -#if __has_include() -#import -#else -@import firebase_storage; -#endif - -#if __has_include() -#import -#else -@import google_sign_in_ios; -#endif - -#if __has_include() -#import -#else -@import image_picker_ios; -#endif - -#if __has_include() -#import -#else -@import path_provider_foundation; -#endif - -@implementation GeneratedPluginRegistrant - -+ (void)registerWithRegistry:(NSObject*)registry { - [DesktopWebviewAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"DesktopWebviewAuthPlugin"]]; - [FilePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FilePickerPlugin"]]; - [FLTFirebaseAnalyticsPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAnalyticsPlugin"]]; - [FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]]; - [FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]]; - [FLTFirebaseDynamicLinksPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseDynamicLinksPlugin"]]; - [FLTFirebaseRemoteConfigPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseRemoteConfigPlugin"]]; - [FLTFirebaseStoragePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseStoragePlugin"]]; - [FLTGoogleSignInPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTGoogleSignInPlugin"]]; - [FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]]; - [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]]; -} - -@end diff --git a/lib/app/modules/dashboard/controllers/dashboard_controller.dart b/lib/app/modules/dashboard/controllers/dashboard_controller.dart index 4732b7b6..24d91a16 100644 --- a/lib/app/modules/dashboard/controllers/dashboard_controller.dart +++ b/lib/app/modules/dashboard/controllers/dashboard_controller.dart @@ -14,9 +14,4 @@ class DashboardController extends GetxController { }, ); } - var isSearchBarVisible = true.obs; - void toggleSearchBarVisibility() { - isSearchBarVisible.value = !isSearchBarVisible.value; - } - // Observable state for current time (example) } diff --git a/lib/app/modules/dashboard/views/dashboard_view.dart b/lib/app/modules/dashboard/views/dashboard_view.dart index 648f164a..f475030f 100644 --- a/lib/app/modules/dashboard/views/dashboard_view.dart +++ b/lib/app/modules/dashboard/views/dashboard_view.dart @@ -1,36 +1,6 @@ -// 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 'package:firebase_remote_config/firebase_remote_config.dart'; -import '../../../../services/remote_config.dart'; import '../controllers/dashboard_controller.dart'; class DashboardView extends GetView { @@ -39,105 +9,20 @@ class DashboardView extends GetView { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Dashboard'), - centerTitle: true, - actions: [ - GetBuilder( - builder: (controller) { - return FutureBuilder( - future: RemoteConfig.instance.then((config) => config.showSearchBarOnTop()), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError || !snapshot.data!) { - return const SizedBox.shrink(); - } else { - return GetPlatform.isMobile - ? PopupMenuButton( - onSelected: (value) { - if (value == 'toggleSearchBar') { - controller.toggleSearchBarVisibility(); - } - }, - itemBuilder: (BuildContext context) { - return [ - PopupMenuItem( - value: 'toggleSearchBar', - child: Row( - children: [ - const Icon(Icons.search), - const SizedBox(width: 8), - const Text('Toggle Search Bar'), - ], - ), - ), - ]; - }, - ) - : const SizedBox.shrink(); - } - }, - ); - }, + body: Center( + child: Obx( + () => Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'DashboardView is working', + style: TextStyle(fontSize: 20), + ), + Text('Time: ${controller.now.value.toString()}'), + ], ), - ], - ), - body: Obx( - () { - // Use the controller's state for search bar visibility - bool isSearchBarVisible = controller.isSearchBarVisible.value; - - return FutureBuilder( - future: RemoteConfig.instance.then((config) => config.showSearchBarOnTop()), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError) { - return Center(child: Text('Error: ${snapshot.error}')); - } else { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (isSearchBarVisible) - Padding( - padding: const EdgeInsets.all(8.0), - child: _buildSearchBar(), - ), - Expanded( - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'DashboardView is working', - style: TextStyle(fontSize: 20), - ), - Text('Time: ${controller.now.value.toString()}'), - ], - ), - ), - ), - ], - ); - } - }, - ); - }, - ), - ); - } - - Widget _buildSearchBar() { - return TextField( - decoration: InputDecoration( - hintText: 'Search...', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0), ), - prefixIcon: Icon(Icons.search), ), ); } } - diff --git a/lib/app/modules/login/controllers/login_controller.dart b/lib/app/modules/login/controllers/login_controller.dart index ce2df429..5178fec9 100644 --- a/lib/app/modules/login/controllers/login_controller.dart +++ b/lib/app/modules/login/controllers/login_controller.dart @@ -1,59 +1,11 @@ -// // 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:firebase_auth/firebase_auth.dart' as fba; -// 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); -// final Rx verificationId = ''.obs; -// final Rxn credential = Rxn(); -// final Rx isPhoneVerified = false.obs; -// -// 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:firebase_auth/firebase_auth.dart' as fba; -import 'package:firebase_auth/firebase_auth.dart'; 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); - final Rx verificationId = ''.obs; - final Rxn credential = - Rxn(); - final Rx isPhoneVerified = false.obs; // New observable bool get isRobot => AuthService.to.robot.value == true; @@ -65,5 +17,4 @@ class LoginController extends GetxController { 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 ce0ea586..00c3af3f 100644 --- a/lib/app/modules/login/views/login_view.dart +++ b/lib/app/modules/login/views/login_view.dart @@ -16,7 +16,6 @@ class LoginView extends GetView { bool show, fba.EmailAuthCredential? credential) { // Below is very important. // See [https://stackoverflow.com/questions/69351845/this-obx-widget-cannot-be-marked-as-needing-to-build-because-the-framework-is-al] - WidgetsBinding.instance.addPostFrameCallback((_) { controller.showReverificationButton.value = show; }); @@ -150,61 +149,6 @@ class EmailLinkButton extends StatelessWidget { }); @override - // Widget loginScreen(BuildContext context) { - // Widget ui; - // bool showPhoneVerification = controller.showReverificationButton.value; - // - // if (!controller.isLoggedIn) { - // ui = !(GetPlatform.isAndroid || GetPlatform.isIOS) && controller.isRobot - // ? recaptcha() - // : SignInScreen( - // providers: [ - // GoogleProvider(clientId: DefaultFirebaseOptions.webClientId), - // MyEmailAuthProvider(), - // ], - // showAuthActionSwitch: !controller.isRegistered, - // showPasswordVisibilityToggle: true, - // headerBuilder: LoginWidgets.headerBuilder, - // subtitleBuilder: subtitleBuilder, - // footerBuilder: (context, action) => footerBuilder( - // controller.showReverificationButton, - // LoginController.to.credential), - // sideBuilder: LoginWidgets.sideBuilder, - // actions: getActions(), - // ); - // } else if (controller.isAnon) { - // ui = RegisterScreen( - // providers: [ - // MyEmailAuthProvider(), - // ], - // showAuthActionSwitch: !controller.isAnon, //if Anon only SignUp - // showPasswordVisibilityToggle: true, - // headerBuilder: LoginWidgets.headerBuilder, - // subtitleBuilder: subtitleBuilder, - // footerBuilder: (context, action) => footerBuilder( - // controller.showReverificationButton, LoginController.to.credential), - // sideBuilder: LoginWidgets.sideBuilder, - // actions: getActions(), - // ); - // } else { - // final thenTo = Get - // .rootDelegate.currentConfiguration!.currentPage!.parameters?['then']; - // Get.rootDelegate.offNamed(thenTo ?? - // (controller.isRegistered ? Screen.HOME : Screen.REGISTER).route); - // ui = const Scaffold(); - // } - // - // // Add phone verification UI below the existing UI components - // return Column( - // crossAxisAlignment: CrossAxisAlignment.stretch, - // children: [ - // ui, // Existing UI - // if (showPhoneVerification) - // phoneVerificationUI(context), - // ], - // ); - // } - Widget build(BuildContext context) { return Obx(() => Visibility( visible: show.value, diff --git a/lib/app/modules/login/views/phone_verification_view.dart b/lib/app/modules/login/views/phone_verification_view.dart deleted file mode 100644 index 960f3362..00000000 --- a/lib/app/modules/login/views/phone_verification_view.dart +++ /dev/null @@ -1,53 +0,0 @@ -// import 'package:flutter/material.dart'; -// import 'package:get/get.dart'; -// import '../controllers/login_controller.dart'; -// -// class PhoneVerificationView extends StatelessWidget { -// final TextEditingController phoneController = TextEditingController(); -// final TextEditingController codeController = TextEditingController(); -// -// @override -// Widget build(BuildContext context) { -// return Scaffold( -// appBar: AppBar( -// title: Text('Phone Verification'), -// ), -// body: Padding( -// padding: const EdgeInsets.all(16.0), -// child: Column( -// children: [ -// TextField( -// controller: phoneController, -// decoration: InputDecoration(labelText: 'Phone Number'), -// ), -// ElevatedButton( -// onPressed: () { -// LoginController.to.verifyPhoneNumber( -// phoneController.text, -// (credential) { -// // Handle verification completed -// Get.snackbar('Success', 'Phone number verified'); -// }, -// ); -// }, -// child: Text('Verify Phone Number'), -// ), -// TextField( -// controller: codeController, -// decoration: InputDecoration(labelText: 'Verification Code'), -// ), -// ElevatedButton( -// onPressed: () { -// LoginController.to.signInWithPhoneNumber( -// LoginController.to.verificationId.value, -// codeController.text, -// ); -// }, -// child: Text('Sign In'), -// ), -// ], -// ), -// ), -// ); -// } -// } diff --git a/lib/app/modules/profile/controllers/profile_controller.dart b/lib/app/modules/profile/controllers/profile_controller.dart index f09baa3a..0c1e059e 100644 --- a/lib/app/modules/profile/controllers/profile_controller.dart +++ b/lib/app/modules/profile/controllers/profile_controller.dart @@ -60,94 +60,3 @@ class ProfileController extends GetxController { 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:flutter/material.dart'; -// import 'package:get/get.dart'; -// import 'package:get_storage/get_storage.dart'; -// import 'package:path/path.dart'; -// import '../../../../services/auth_service.dart'; -// -// // Define the Persona class -// class Persona { -// final String name; -// final String imagePath; -// final bool isDarkTheme; -// -// Persona({required this.name, required this.imagePath, required this.isDarkTheme}); -// } -// -// // List of personas -// final List personas = [ -// Persona(name: 'Default', imagePath: 'assets/persona/default.png', isDarkTheme: false), -// Persona(name: 'Kids', imagePath: 'assets/persona/kids.png', isDarkTheme: false), -// Persona(name: 'Dark', imagePath: 'assets/persona/dark.png', isDarkTheme: true), -// ]; -// -// class ProfileController extends GetxController { -// FirebaseStorage storage = FirebaseStorage.instance; -// User? currentUser = AuthService.to.user; -// final Rxn _photoURL = Rxn(); -// final RxString selectedPersona = 'Default'.obs; -// -// File? _photo; -// -// String? get photoURL => _photoURL.value; -// -// @override -// void onInit() { -// super.onInit(); -// _photoURL.value = currentUser!.photoURL; -// _photoURL.bindStream(currentUser!.photoURL.obs.stream); -// selectedPersona.value = GetStorage().read('selectedPersona') ?? 'Default'; -// } -// -// 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; -// } -// -// 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'); -// } -// -// void logout() { -// AuthService.to.logout(); -// } -// -// void updatePersona(String persona) { -// selectedPersona.value = persona; -// GetStorage().write('selectedPersona', persona); -// applyPersonaSettings(persona); -// } -// -// void applyPersonaSettings(String persona) { -// final selected = personas.firstWhere((p) => p.name == persona); -// Get.changeTheme(selected.isDarkTheme ? ThemeData.dark() : ThemeData.light()); -// // Add any other persona-specific settings here -// } -// } diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index dbb1432a..1b6ed535 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -143,161 +143,3 @@ class ProfileView extends GetView { } } } - -// 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 '../../../../models/screens.dart'; -// import '../../../utils/img_constants.dart'; -// import '../../../widgets/change_password_dialog.dart'; -// import '../../../widgets/image_picker_button.dart'; -// import '../controllers/profile_controller.dart'; -// -// class ProfileView extends GetView { -// const ProfileView({super.key}); -// ShapeBorder get shape => const CircleBorder(); -// double get size => 120; -// Color get placeholderColor => Colors.grey; -// -// Widget _imageFrameBuilder( -// BuildContext context, -// Widget? child, -// int? frame, -// bool? _, -// ) { -// if (frame == null) { -// return Container(color: placeholderColor); -// } -// -// return child!; -// } -// -// @override -// Widget build(BuildContext context) { -// return Obx(() => profileScreen()); -// } -// -// Widget profileScreen() { -// return AuthService.to.isLoggedInValue -// ? ProfileScreen( -// avatar: SizedBox( -// 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( -// ImgConstants.dash, -// width: size, -// fit: BoxFit.contain, -// ), -// ), -// ), -// ), -// actions: [ -// SignedOutAction((context) { -// Get.back(); -// controller.logout(); -// Get.rootDelegate.toNamed(Screen.PROFILE.route); -// }), -// AccountDeletedAction((context, user) { -// Get.defaultDialog( -// title: 'Deleted Account of ${user.displayName}', -// barrierDismissible: true, -// navigatorKey: Get.nestedKey(Screen.HOME.route), -// ); -// }) -// ], -// children: [ -// 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) { -// String? dest = await controller.uploadFile(path); -// if (dest != null) { -// await controller.updatePhotoURL(dest); -// } -// } -// }), -// const Divider(), -// Padding( -// padding: const EdgeInsets.all(8.0), -// child: Text('Select Persona:', style: TextStyle(fontSize: 18)), -// ), -// Expanded( -// child: PersonaSelection( -// personas: personas, -// onPersonaSelected: (persona) { -// controller.updatePersona(persona); -// }, -// ), -// ), -// ], -// ) -// : const Scaffold(); -// } -// -// void callChangePwdDialog() { -// var dlg = ChangePasswordDialog(controller.currentUser!); -// Get.defaultDialog( -// title: "Change Password", -// content: dlg, -// textConfirm: "Submit", -// textCancel: "Cancel", -// onConfirm: dlg.onSubmit); -// } -// } -// -// class PersonaSelection extends StatelessWidget { -// final List personas; -// final ValueChanged onPersonaSelected; -// -// PersonaSelection({required this.personas, required this.onPersonaSelected}); -// -// @override -// Widget build(BuildContext context) { -// return GridView.builder( -// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( -// crossAxisCount: 2, -// childAspectRatio: 1, -// ), -// itemCount: personas.length, -// itemBuilder: (context, index) { -// final persona = personas[index]; -// return GestureDetector( -// onTap: () { -// onPersonaSelected(persona.name); -// Get.snackbar('Persona Selected', '${persona.name} persona applied!'); -// }, -// child: Card( -// child: Column( -// children: [ -// Image.asset(persona.imagePath, height: 100, width: 100), -// Text(persona.name), -// ], -// ), -// ), -// ); -// }, -// ); -// } -// } diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 908fdd62..a6bef783 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -190,8 +190,6 @@ class AuthService extends GetxService { }; }; } - - //void verifyPhoneNumber(String text, Null Function(dynamic credential) param1) {} } class MyCredential extends AuthCredential { @@ -210,4 +208,3 @@ parseEmail(String message) { int j = message.indexOf('"', i); return message.substring(i, j - 1); } - diff --git a/lib/services/phone_auth_screen.dart b/lib/services/phone_auth_screen.dart deleted file mode 100644 index d2c34f59..00000000 --- a/lib/services/phone_auth_screen.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:flutter/material.dart'; - -class PhoneAuthScreen extends StatefulWidget { - @override - _PhoneAuthScreenState createState() => _PhoneAuthScreenState(); -} - -class _PhoneAuthScreenState extends State { - late String _verificationId; - late TextEditingController _phoneNumberController; - late TextEditingController _smsController; - - @override - void initState() { - super.initState(); - _phoneNumberController = TextEditingController(); - _smsController = TextEditingController(); - } - - @override - void dispose() { - _phoneNumberController.dispose(); - _smsController.dispose(); - super.dispose(); - } - - Future _verifyPhoneNumber() async { - await FirebaseAuth.instance.verifyPhoneNumber( - phoneNumber: '+91${_phoneNumberController.text}', - verificationCompleted: (PhoneAuthCredential credential) async { - // Auto-retrieve the SMS code and sign in - await FirebaseAuth.instance.signInWithCredential(credential); - // Navigate to your desired screen after authentication - }, - verificationFailed: (FirebaseAuthException e) { - // Handle verification failed - print(e.message); - }, - codeSent: (String verificationId, int? resendToken) { - setState(() { - _verificationId = verificationId; - }); - }, - codeAutoRetrievalTimeout: (String verificationId) { - setState(() { - _verificationId = verificationId; - }); - }, - ); - } - - void _signInWithPhoneNumber() async { - try { - final credential = PhoneAuthProvider.credential( - verificationId: _verificationId, - smsCode: _smsController.text, - ); - await FirebaseAuth.instance.signInWithCredential(credential); - // Navigate to your desired screen after authentication - } catch (e) { - print(e.toString()); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Phone Authentication'), - ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - TextField( - controller: _phoneNumberController, - decoration: InputDecoration(labelText: 'Enter phone number'), - keyboardType: TextInputType.phone, - ), - SizedBox(height: 16.0), - ElevatedButton( - onPressed: _verifyPhoneNumber, - child: Text('Verify Phone Number'), - ), - SizedBox(height: 16.0), - Visibility( - visible: _verificationId != null, - child: Column( - children: [ - TextField( - controller: _smsController, - decoration: InputDecoration(labelText: 'Enter SMS Code'), - keyboardType: TextInputType.number, - ), - SizedBox(height: 16.0), - ElevatedButton( - onPressed: _signInWithPhoneNumber, - child: Text('Sign In with SMS Code'), - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig deleted file mode 100644 index 75656d0a..00000000 --- a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig +++ /dev/null @@ -1,11 +0,0 @@ -// This is a generated file; do not edit or check into version control. -FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter -FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire -COCOAPODS_PARALLEL_CODE_SIGN=true -FLUTTER_BUILD_DIR=build -FLUTTER_BUILD_NAME=1.0.0 -FLUTTER_BUILD_NUMBER=1 -DART_OBFUSCATION=false -TRACK_WIDGET_CREATION=true -TREE_SHAKE_ICONS=false -PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/macos/Flutter/ephemeral/flutter_export_environment.sh b/macos/Flutter/ephemeral/flutter_export_environment.sh deleted file mode 100644 index accf248b..00000000 --- a/macos/Flutter/ephemeral/flutter_export_environment.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=C:\Users\Aastha Gadhvi\Downloads\flutter_windows_3.10.5-stable\flutter" -export "FLUTTER_APPLICATION_PATH=C:\Users\Aastha Gadhvi\get-flutter-fire" -export "COCOAPODS_PARALLEL_CODE_SIGN=true" -export "FLUTTER_BUILD_DIR=build" -export "FLUTTER_BUILD_NAME=1.0.0" -export "FLUTTER_BUILD_NUMBER=1" -export "DART_OBFUSCATION=false" -export "TRACK_WIDGET_CREATION=true" -export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/pubspec.lock b/pubspec.lock index f7672bfa..d0fdd9cb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -597,14 +597,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" path: dependency: "direct main" description: @@ -693,14 +685,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - provider: - dependency: "direct main" - description: - name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c - url: "https://pub.dev" - source: hosted - version: "6.1.2" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index bf263fec..d000e5f5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,7 +10,6 @@ dependencies: get: 4.6.6 flutter: sdk: flutter - provider: ^6.1.2 firebase_core: ^2.31.0 firebase_ui_auth: ^1.14.0 firebase_auth: ^4.19.5 From a5a56a5b5f39ee530fa7eac2bfbba9ba1c2c29f6 Mon Sep 17 00:00:00 2001 From: Anshuman Das Date: Sat, 20 Jul 2024 12:51:06 +0530 Subject: [PATCH 21/23] Revert "Feature/reset password email verification" --- .metadata | 25 +- android/app/google-services.json | 82 ----- .../example/get_flutter_fire/MainActivity.kt | 5 - ios/Podfile | 44 --- ios/Podfile.lock | 346 ------------------ ios/Runner/GoogleService-Info.plist | 34 -- .../modules/profile/views/profile_view.dart | 188 +++++----- lib/app/widgets/image_picker_button.dart | 55 +-- macos/Podfile | 43 --- macos/Runner/GoogleService-Info.plist | 34 -- pubspec.lock | 88 ++--- 11 files changed, 150 insertions(+), 794 deletions(-) delete mode 100644 android/app/google-services.json delete mode 100644 android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt delete mode 100644 ios/Podfile delete mode 100644 ios/Podfile.lock delete mode 100644 ios/Runner/GoogleService-Info.plist delete mode 100644 macos/Podfile delete mode 100644 macos/Runner/GoogleService-Info.plist diff --git a/.metadata b/.metadata index 6eb54a17..784ce129 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" + revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" channel: "stable" project_type: app @@ -13,26 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: android - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: ios - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: linux - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: macos - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 - platform: web - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - - platform: windows - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 # User provided section diff --git a/android/app/google-services.json b/android/app/google-services.json deleted file mode 100644 index 41ea6bf4..00000000 --- a/android/app/google-services.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "project_info": { - "project_number": "56053565487", - "project_id": "sharekhan-nemin", - "storage_bucket": "sharekhan-nemin.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:56053565487:android:f0e57a6359c84f97cb5eda", - "android_client_info": { - "package_name": "nemin.sharekhan" - } - }, - "oauth_client": [ - { - "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyA42S1sFkyQAj1yZ1F4gUmE_pxec3h3YBw" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "com.example.getFlutterFire" - } - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:56053565487:android:a10bbf5abca35d98cb5eda", - "android_client_info": { - "package_name": "sharekhan.nemin" - } - }, - "oauth_client": [ - { - "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyA42S1sFkyQAj1yZ1F4gUmE_pxec3h3YBw" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "56053565487-rbb4oliis6kl4angm8pbu9dusnr5g4op.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "com.example.getFlutterFire" - } - } - ] - } - } - } - ], - "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 deleted file mode 100644 index 018e286b..00000000 --- a/android/app/src/main/kotlin/com/example/get_flutter_fire/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.get_flutter_fire - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() diff --git a/ios/Podfile b/ios/Podfile deleted file mode 100644 index d97f17e2..00000000 --- a/ios/Podfile +++ /dev/null @@ -1,44 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '12.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/ios/Podfile.lock b/ios/Podfile.lock deleted file mode 100644 index 6afd14af..00000000 --- a/ios/Podfile.lock +++ /dev/null @@ -1,346 +0,0 @@ -PODS: - - AppAuth (1.7.5): - - AppAuth/Core (= 1.7.5) - - AppAuth/ExternalUserAgent (= 1.7.5) - - AppAuth/Core (1.7.5) - - AppAuth/ExternalUserAgent (1.7.5): - - AppAuth/Core - - desktop_webview_auth (0.0.1): - - Flutter - - DKImagePickerController/Core (4.3.9): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.9) - - DKImagePickerController/PhotoGallery (4.3.9): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.9) - - DKPhotoGallery (0.0.19): - - DKPhotoGallery/Core (= 0.0.19) - - DKPhotoGallery/Model (= 0.0.19) - - DKPhotoGallery/Preview (= 0.0.19) - - DKPhotoGallery/Resource (= 0.0.19) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.19): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.19): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - - Firebase/Analytics (10.25.0): - - Firebase/Core - - Firebase/Auth (10.25.0): - - Firebase/CoreOnly - - FirebaseAuth (~> 10.25.0) - - Firebase/Core (10.25.0): - - Firebase/CoreOnly - - FirebaseAnalytics (~> 10.25.0) - - Firebase/CoreOnly (10.25.0): - - FirebaseCore (= 10.25.0) - - Firebase/DynamicLinks (10.25.0): - - Firebase/CoreOnly - - FirebaseDynamicLinks (~> 10.25.0) - - Firebase/RemoteConfig (10.25.0): - - Firebase/CoreOnly - - FirebaseRemoteConfig (~> 10.25.0) - - Firebase/Storage (10.25.0): - - Firebase/CoreOnly - - FirebaseStorage (~> 10.25.0) - - firebase_analytics (10.10.7): - - Firebase/Analytics (= 10.25.0) - - firebase_core - - Flutter - - firebase_auth (4.20.0): - - Firebase/Auth (= 10.25.0) - - firebase_core - - Flutter - - firebase_core (2.32.0): - - Firebase/CoreOnly (= 10.25.0) - - Flutter - - firebase_dynamic_links (5.5.7): - - Firebase/DynamicLinks (= 10.25.0) - - firebase_core - - Flutter - - firebase_remote_config (4.4.7): - - Firebase/RemoteConfig (= 10.25.0) - - firebase_core - - Flutter - - firebase_storage (11.7.7): - - Firebase/Storage (= 10.25.0) - - firebase_core - - Flutter - - FirebaseABTesting (10.29.0): - - FirebaseCore (~> 10.0) - - FirebaseAnalytics (10.25.0): - - FirebaseAnalytics/AdIdSupport (= 10.25.0) - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - - GoogleUtilities/MethodSwizzler (~> 7.11) - - GoogleUtilities/Network (~> 7.11) - - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30911.0, >= 2.30908.0) - - FirebaseAnalytics/AdIdSupport (10.25.0): - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleAppMeasurement (= 10.25.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - - GoogleUtilities/MethodSwizzler (~> 7.11) - - GoogleUtilities/Network (~> 7.11) - - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30911.0, >= 2.30908.0) - - FirebaseAppCheckInterop (10.29.0) - - FirebaseAuth (10.25.0): - - FirebaseAppCheckInterop (~> 10.17) - - FirebaseCore (~> 10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/Environment (~> 7.8) - - GTMSessionFetcher/Core (< 4.0, >= 2.1) - - RecaptchaInterop (~> 100.0) - - FirebaseAuthInterop (10.29.0) - - FirebaseCore (10.25.0): - - FirebaseCoreInternal (~> 10.0) - - GoogleUtilities/Environment (~> 7.12) - - GoogleUtilities/Logger (~> 7.12) - - FirebaseCoreExtension (10.29.0): - - FirebaseCore (~> 10.0) - - FirebaseCoreInternal (10.29.0): - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseDynamicLinks (10.25.0): - - FirebaseCore (~> 10.0) - - FirebaseInstallations (10.29.0): - - FirebaseCore (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/UserDefaults (~> 7.8) - - PromisesObjC (~> 2.1) - - FirebaseRemoteConfig (10.25.0): - - FirebaseABTesting (~> 10.0) - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - FirebaseRemoteConfigInterop (~> 10.23) - - FirebaseSharedSwift (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseRemoteConfigInterop (10.29.0) - - FirebaseSharedSwift (10.29.0) - - FirebaseStorage (10.25.0): - - FirebaseAppCheckInterop (~> 10.0) - - FirebaseAuthInterop (~> 10.25) - - FirebaseCore (~> 10.0) - - FirebaseCoreExtension (~> 10.0) - - GoogleUtilities/Environment (~> 7.12) - - GTMSessionFetcher/Core (< 4.0, >= 2.1) - - Flutter (1.0.0) - - google_sign_in_ios (0.0.1): - - AppAuth (>= 1.7.4) - - Flutter - - FlutterMacOS - - GoogleSignIn (~> 7.1) - - GTMSessionFetcher (>= 3.4.0) - - GoogleAppMeasurement (10.25.0): - - GoogleAppMeasurement/AdIdSupport (= 10.25.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - - GoogleUtilities/MethodSwizzler (~> 7.11) - - GoogleUtilities/Network (~> 7.11) - - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30911.0, >= 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (10.25.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 10.25.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - - GoogleUtilities/MethodSwizzler (~> 7.11) - - GoogleUtilities/Network (~> 7.11) - - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30911.0, >= 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (10.25.0): - - GoogleUtilities/AppDelegateSwizzler (~> 7.11) - - GoogleUtilities/MethodSwizzler (~> 7.11) - - GoogleUtilities/Network (~> 7.11) - - "GoogleUtilities/NSData+zlib (~> 7.11)" - - nanopb (< 2.30911.0, >= 2.30908.0) - - GoogleSignIn (7.1.0): - - AppAuth (< 2.0, >= 1.7.3) - - GTMAppAuth (< 5.0, >= 4.1.1) - - GTMSessionFetcher/Core (~> 3.3) - - GoogleUtilities/AppDelegateSwizzler (7.13.3): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Privacy - - GoogleUtilities/Environment (7.13.3): - - GoogleUtilities/Privacy - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.13.3): - - GoogleUtilities/Environment - - GoogleUtilities/Privacy - - GoogleUtilities/MethodSwizzler (7.13.3): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilities/Network (7.13.3): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Privacy - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.13.3)": - - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (7.13.3) - - GoogleUtilities/Reachability (7.13.3): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilities/UserDefaults (7.13.3): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GTMAppAuth (4.1.1): - - AppAuth/Core (~> 1.7) - - GTMSessionFetcher/Core (< 4.0, >= 3.3) - - GTMSessionFetcher (3.5.0): - - GTMSessionFetcher/Full (= 3.5.0) - - GTMSessionFetcher/Core (3.5.0) - - GTMSessionFetcher/Full (3.5.0): - - GTMSessionFetcher/Core - - image_picker_ios (0.0.1): - - Flutter - - nanopb (2.30910.0): - - nanopb/decode (= 2.30910.0) - - nanopb/encode (= 2.30910.0) - - nanopb/decode (2.30910.0) - - nanopb/encode (2.30910.0) - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - PromisesObjC (2.4.0) - - RecaptchaInterop (100.0.0) - - SDWebImage (5.19.4): - - SDWebImage/Core (= 5.19.4) - - SDWebImage/Core (5.19.4) - - SwiftyGif (5.4.5) - -DEPENDENCIES: - - desktop_webview_auth (from `.symlinks/plugins/desktop_webview_auth/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) - - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - - firebase_dynamic_links (from `.symlinks/plugins/firebase_dynamic_links/ios`) - - firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`) - - firebase_storage (from `.symlinks/plugins/firebase_storage/ios`) - - Flutter (from `Flutter`) - - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - -SPEC REPOS: - trunk: - - AppAuth - - DKImagePickerController - - DKPhotoGallery - - Firebase - - FirebaseABTesting - - FirebaseAnalytics - - FirebaseAppCheckInterop - - FirebaseAuth - - FirebaseAuthInterop - - FirebaseCore - - FirebaseCoreExtension - - FirebaseCoreInternal - - FirebaseDynamicLinks - - FirebaseInstallations - - FirebaseRemoteConfig - - FirebaseRemoteConfigInterop - - FirebaseSharedSwift - - FirebaseStorage - - GoogleAppMeasurement - - GoogleSignIn - - GoogleUtilities - - GTMAppAuth - - GTMSessionFetcher - - nanopb - - PromisesObjC - - RecaptchaInterop - - SDWebImage - - SwiftyGif - -EXTERNAL SOURCES: - desktop_webview_auth: - :path: ".symlinks/plugins/desktop_webview_auth/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" - firebase_analytics: - :path: ".symlinks/plugins/firebase_analytics/ios" - firebase_auth: - :path: ".symlinks/plugins/firebase_auth/ios" - firebase_core: - :path: ".symlinks/plugins/firebase_core/ios" - firebase_dynamic_links: - :path: ".symlinks/plugins/firebase_dynamic_links/ios" - firebase_remote_config: - :path: ".symlinks/plugins/firebase_remote_config/ios" - firebase_storage: - :path: ".symlinks/plugins/firebase_storage/ios" - Flutter: - :path: Flutter - google_sign_in_ios: - :path: ".symlinks/plugins/google_sign_in_ios/darwin" - image_picker_ios: - :path: ".symlinks/plugins/image_picker_ios/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" - -SPEC CHECKSUMS: - AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa - desktop_webview_auth: d645139460ef203d50bd0cdb33356785dd939cce - DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c - DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 - Firebase: 0312a2352584f782ea56f66d91606891d4607f06 - firebase_analytics: cc06e24d6a2343c44f845b3112143db72d10ef78 - firebase_auth: 5719ddc9f654b813405899480e84971bd8e61235 - firebase_core: a626d00494efa398e7c54f25f1454a64c8abf197 - firebase_dynamic_links: 525e9c1b702d2ed2d9b0dbd342eee1e15a75e62d - firebase_remote_config: 7b05c80210ab558c80f7a756681022b4ee98eea0 - firebase_storage: 5c0f552d6b27d621429d7fd16ebab4be94a3c954 - FirebaseABTesting: d87f56707159bae64e269757a6e963d490f2eebe - FirebaseAnalytics: ec00fe8b93b41dc6fe4a28784b8e51da0647a248 - FirebaseAppCheckInterop: 6a1757cfd4067d8e00fccd14fcc1b8fd78cfac07 - FirebaseAuth: c0f93dcc570c9da2bffb576969d793e95c344fbb - FirebaseAuthInterop: 17db81e9b198afb0f95ce48c133825727eed55d3 - FirebaseCore: 7ec4d0484817f12c3373955bc87762d96842d483 - FirebaseCoreExtension: 705ca5b14bf71d2564a0ddc677df1fc86ffa600f - FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934 - FirebaseDynamicLinks: 12c9f5b643943e0565ed28080373f89cbcb914a3 - FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd - FirebaseRemoteConfig: 9f3935cefecd85d5b312192117f444957de24a75 - FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d - FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e - FirebaseStorage: 44f4e25073f6fa0d4d8c09f5bec299ee9e4eb985 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - google_sign_in_ios: 07375bfbf2620bc93a602c0e27160d6afc6ead38 - GoogleAppMeasurement: 9abf64b682732fed36da827aa2a68f0221fd2356 - GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db - GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 - GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de - GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 - image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 - nanopb: 438bc412db1928dac798aa6fd75726007be04262 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21 - SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d - SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 - -PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 - -COCOAPODS: 1.14.2 diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist deleted file mode 100644 index 78e3a245..00000000 --- a/ios/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CLIENT_ID - 56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo - API_KEY - AIzaSyD12e9qHOj8ulb6cxP0DIWHW2tIeYzgKtc - GCM_SENDER_ID - 56053565487 - PLIST_VERSION - 1 - BUNDLE_ID - com.example.getFlutterFire - PROJECT_ID - sharekhan-nemin - STORAGE_BUCKET - sharekhan-nemin.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:56053565487:ios:3515d315addadb07cb5eda - - \ No newline at end of file diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index 1b6ed535..cd9b8e28 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -1,6 +1,5 @@ // ignore_for_file: inference_failure_on_function_invocation -import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_ui_auth/firebase_ui_auth.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -19,11 +18,11 @@ class ProfileView extends GetView { Color get placeholderColor => Colors.grey; Widget _imageFrameBuilder( - BuildContext context, - Widget? child, - int? frame, - bool? _, - ) { + BuildContext context, + Widget? child, + int? frame, + bool? _, + ) { if (frame == null) { return Container(color: placeholderColor); } @@ -33,113 +32,94 @@ class ProfileView extends GetView { @override Widget build(BuildContext context) { - return Obx(() => profileScreen(context)); + return Obx(() => profileScreen()); } - Widget profileScreen(BuildContext context) { + Widget profileScreen() { return AuthService.to.isLoggedInValue ? ProfileScreen( - // We are using the Flutter Fire Profile Screen now but will change in subsequent steps. - // The issues are highlighted in comments here + // 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', + // 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, - fit: BoxFit.contain, + 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( + ImgConstants.dash, + 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: () => _resetPasswordEmailVerification(context), - label: const Text('Reset Password'), - icon: const Icon(Icons.email_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); - } - } - }) - ], - ) + // 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); + } + } + }) + ], + ) : const Scaffold(); } - - - Future _resetPasswordEmailVerification(BuildContext context) async { - final email = controller.currentUser?.email; - if (email != null) { - try { - await FirebaseAuth.instance.sendPasswordResetEmail(email: email); - controller.logout(); - Get.snackbar( - 'Success', - 'Password reset email sent. Please check your inbox.', - snackPosition: SnackPosition.BOTTOM, - ); - } catch (e) { - Get.snackbar( - 'Error', - 'Failed to send password reset email: $e', - snackPosition: SnackPosition.BOTTOM, - ); - } - } else { - Get.snackbar( - 'Error', - 'No email associated with this account.', - snackPosition: SnackPosition.BOTTOM, - ); - } + void callChangePwdDialog() { + var dlg = ChangePasswordDialog(controller.currentUser!); + Get.defaultDialog( + title: "Change Password", + content: dlg, + textConfirm: "Submit", + textCancel: "Cancel", + onConfirm: dlg.onSubmit); } } diff --git a/lib/app/widgets/image_picker_button.dart b/lib/app/widgets/image_picker_button.dart index dbd504ef..d6e87ff4 100644 --- a/lib/app/widgets/image_picker_button.dart +++ b/lib/app/widgets/image_picker_button.dart @@ -44,38 +44,16 @@ enum ImageSources implements ActionEnum { } static Future getFile() async { - if (GetPlatform.isWeb) { - // Web-specific file picking logic - return await getWebFile(); - } else { - 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; - } else { - Get.snackbar('Error', 'Image Not Selected'); - return null; - } - } - } - - static Future getWebFile() async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.image, - allowMultiple: false, - ); + 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; @@ -86,12 +64,11 @@ enum ImageSources implements ActionEnum { class ImagePickerButton extends MenuSheetButton { final ValueSetter? callback; - const ImagePickerButton({ - super.key, - super.icon = const Icon(Icons.image), - super.label = 'Pick an Image', - this.callback, - }); + const ImagePickerButton( + {super.key, + super.icon = const Icon(Icons.image), + super.label = 'Pick an Image', + this.callback}); @override Iterable get values => ImageSources.values; @@ -103,10 +80,12 @@ class ImagePickerButton extends MenuSheetButton { @override Widget build(BuildContext context) { - return TextButton.icon( - onPressed: () async => callbackFunc(await ImageSources.getFile()), - icon: icon, - label: const Text('Pick an Image'), - ); + return !(GetPlatform.isAndroid || GetPlatform.isIOS) + ? TextButton.icon( + onPressed: () async => callbackFunc(await ImageSources.getFile()), + icon: icon, + label: const Text('Pick an Image'), + ) + : builder(context); } -} \ No newline at end of file +} diff --git a/macos/Podfile b/macos/Podfile deleted file mode 100644 index c795730d..00000000 --- a/macos/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -platform :osx, '10.14' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/macos/Runner/GoogleService-Info.plist b/macos/Runner/GoogleService-Info.plist deleted file mode 100644 index 78e3a245..00000000 --- a/macos/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CLIENT_ID - 56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.56053565487-4hpe201r97dakjqqo6b0g3ltrabpfrmo - API_KEY - AIzaSyD12e9qHOj8ulb6cxP0DIWHW2tIeYzgKtc - GCM_SENDER_ID - 56053565487 - PLIST_VERSION - 1 - BUNDLE_ID - com.example.getFlutterFire - PROJECT_ID - sharekhan-nemin - STORAGE_BUCKET - sharekhan-nemin.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:56053565487:ios:3515d315addadb07cb5eda - - \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index d0fdd9cb..877fc75e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -117,10 +117,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "824f5b9f389bfc4dddac3dea76cd70c51092d9dff0b2ece7ef4f53db8547d258" + sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a" url: "https://pub.dev" source: hosted - version: "8.0.6" + version: "8.0.3" file_selector_linux: dependency: transitive description: @@ -181,26 +181,26 @@ packages: dependency: "direct main" description: name: firebase_auth - sha256: cfc2d970829202eca09e2896f0a5aa7c87302817ecc0bdfa954f026046bf10ba + sha256: f0a75f61992d036e4c46ad0e9febd364d98aa2c092690a5475cb1421a8243cfe url: "https://pub.dev" source: hosted - version: "4.20.0" + version: "4.19.5" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: a0270e1db3b2098a14cb2a2342b3cd2e7e458e0c391b1f64f6f78b14296ec093 + sha256: feb77258404309ffc7761c78e1c0ad2ed5e4fdc378e035619e2cc13be4397b62 url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.2.6" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: "64e067e763c6378b7e774e872f0f59f6812885e43020e25cde08f42e9459837b" + sha256: "6d527f357da2bf93a67a42b423aa92943104a0c290d1d72ad9a42c779d501cd2" url: "https://pub.dev" source: hosted - version: "5.12.0" + version: "5.11.5" firebase_core: dependency: "direct main" description: @@ -213,34 +213,34 @@ packages: dependency: transitive description: name: firebase_core_platform_interface - sha256: "1003a5a03a61fc9a22ef49f37cbcb9e46c86313a7b2e7029b9390cf8c6fc32cb" + sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.0.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "23509cb3cddfb3c910c143279ac3f07f06d3120f7d835e4a5d4b42558e978712" + sha256: "43d9e951ac52b87ae9cc38ecdcca1e8fa7b52a1dd26a96085ba41ce5108db8e9" url: "https://pub.dev" source: hosted - version: "2.17.3" + version: "2.17.0" firebase_dynamic_links: dependency: transitive description: name: firebase_dynamic_links - sha256: "47b8c8a8546d8a7f9000edb90848549f20b137d814ee7e0407b3d43b8445e282" + sha256: f704859abc17d99e74b47eaf47455b45a88ab7e2973f03e6130ff666b45fe11f url: "https://pub.dev" source: hosted - version: "5.5.7" + version: "5.5.5" firebase_dynamic_links_platform_interface: dependency: transitive description: name: firebase_dynamic_links_platform_interface - sha256: "72e7810635f908ce060c5803c7acb29116c5b6befc73e90446c52722bc9506a2" + sha256: f86992605b50e2f0ce6c24993430affc98021da8d8a74d5596b7a2c84196c110 url: "https://pub.dev" source: hosted - version: "0.2.6+35" + version: "0.2.6+33" firebase_remote_config: dependency: "direct main" description: @@ -269,26 +269,26 @@ packages: dependency: "direct main" description: name: firebase_storage - sha256: "2ae478ceec9f458c1bcbf0ee3e0100e4e909708979e83f16d5d9fba35a5b42c1" + sha256: da76ca9c11d795c4bae1bd13b31d54bb9eb9ccbee7eb5f6b86b8294370e9d488 url: "https://pub.dev" source: hosted - version: "11.7.7" + version: "11.7.5" firebase_storage_platform_interface: dependency: transitive description: name: firebase_storage_platform_interface - sha256: "4e18662e6a66e2e0e181c06f94707de06d5097d70cfe2b5141bf64660c5b5da9" + sha256: be17bfa9110a6429b40dd3760c755034079fd734aa1dd2476d5638ab780cc508 url: "https://pub.dev" source: hosted - version: "5.1.22" + version: "5.1.20" firebase_storage_web: dependency: transitive description: name: firebase_storage_web - sha256: "3a44aacd38a372efb159f6fe36bb4a7d79823949383816457fd43d3d47602a53" + sha256: "5219c20c0768a8e2ffedf0a116b7bc80ab32fcc6e2cbd50cbde14f8c4575c3f4" url: "https://pub.dev" source: hosted - version: "3.9.7" + version: "3.9.5" firebase_ui_auth: dependency: "direct main" description: @@ -351,10 +351,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e + sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" url: "https://pub.dev" source: hosted - version: "2.0.20" + version: "2.0.19" flutter_svg: dependency: transitive description: @@ -417,10 +417,10 @@ packages: dependency: transitive description: name: google_sign_in_android - sha256: d30fb34b659679ea74397e9748b4ab5d720720d57dcc79538f1b3c4a68654cb3 + sha256: "7647893c65e6720973f0e579051c8f84b877b486614d9f70a404259c41a4632e" url: "https://pub.dev" source: hosted - version: "6.1.27" + version: "6.1.23" google_sign_in_ios: dependency: transitive description: @@ -441,10 +441,10 @@ packages: dependency: transitive description: name: google_sign_in_web - sha256: d606264c7a1a526a3aa79d938b85a601d8589731a478bd4a3dcbdeb14a572228 + sha256: fc0f14ed45ea616a6cfb4d1c7534c2221b7092cc4f29a709f0c3053cc3e821bd url: "https://pub.dev" source: hosted - version: "0.12.4+1" + version: "0.12.4" http: dependency: transitive description: @@ -465,18 +465,18 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: ff39a10ab4f48f4ac70776d0494a97bf073cd2570892cd46bc8a5cac162c25db + sha256: "79455f6cff4cbef583b2b524bbf0d4ec424e5959f4d464e36ef5323715b98370" url: "https://pub.dev" source: hosted - version: "0.8.12+4" + version: "0.8.12" image_picker_for_web: dependency: transitive description: @@ -489,10 +489,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447" + sha256: cb0db0ec0d3e2cd49674f2e6053be25ccdb959832607c1cbd215dd6cf10fb0dd url: "https://pub.dev" source: hosted - version: "0.8.12" + version: "0.8.11" image_picker_linux: dependency: transitive description: @@ -625,10 +625,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d url: "https://pub.dev" source: hosted - version: "2.2.7" + version: "2.2.4" path_provider_foundation: dependency: transitive description: @@ -657,10 +657,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.2.1" petitparser: dependency: transitive description: @@ -673,10 +673,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: @@ -798,10 +798,10 @@ packages: dependency: transitive description: name: win32 - sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 + sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" url: "https://pub.dev" source: hosted - version: "5.5.1" + version: "5.5.0" xdg_directories: dependency: transitive description: @@ -819,5 +819,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.3.4 <4.0.0" + flutter: ">=3.19.2" From 1d51db9faeacca547525ce03d9b3a76e305feb9f Mon Sep 17 00:00:00 2001 From: vedantbhawnani Date: Sun, 21 Jul 2024 00:50:32 +0530 Subject: [PATCH 22/23] resolved conflicts --- .gitignore | 1 + lib/models/screens.dart | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 8ab3b859..0cdd1ba4 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ migrate_working_dir/ /build/ node_modules +android/app/google-services.json # Symbolication related app.*.symbols diff --git a/lib/models/screens.dart b/lib/models/screens.dart index fda2516f..601f4940 100644 --- a/lib/models/screens.dart +++ b/lib/models/screens.dart @@ -41,11 +41,6 @@ enum Screen implements ActionEnum { parent: HOME), PRODUCT_DETAILS('/:productId', accessLevel: AccessLevel.public, parent: PRODUCTS), - - LOGIN('/login', - icon: Icons.login, - accessor_: AccessedVia.widget, - accessLevel: AccessLevel.notAuthed), SIGNUP('/signUp', icon: Icons.login, accessor_: AccessedVia.widget, From 2d10cc69ee3469cd77af4cb983c23ea5455817d7 Mon Sep 17 00:00:00 2001 From: vedantbhawnani Date: Mon, 22 Jul 2024 00:36:59 +0530 Subject: [PATCH 23/23] fix/sign up method --- lib/app/modules/login/views/custom_signUp.dart | 2 +- lib/services/auth_service.dart | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/app/modules/login/views/custom_signUp.dart b/lib/app/modules/login/views/custom_signUp.dart index 1b562803..de452068 100644 --- a/lib/app/modules/login/views/custom_signUp.dart +++ b/lib/app/modules/login/views/custom_signUp.dart @@ -82,7 +82,7 @@ class CustomSignUp extends GetView { } else if (passwordController.text == confirmpasswordController.text) { AuthService() - .login(emailController.text, passwordController.text); + .signUp(emailController.text, passwordController.text); } }, child: Container( diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 1c849e58..e2f261c6 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -137,6 +137,24 @@ class AuthService extends GetxService { } } + Future signUp(String email, String password) async { + try { + final credential = + await FirebaseAuth.instance.createUserWithEmailAndPassword( + email: email, + password: password, + ); + } on FirebaseAuthException catch (e) { + if (e.code == 'weak-password') { + print('The password provided is too weak.'); + } else if (e.code == 'email-already-in-use') { + print('The account already exists for that email.'); + } + } catch (e) { + print(e); + } + } + Future login(String email, String password) async { // isLoading.value = true; try {