From ad6278cf8bf256c1ac7923572f676d80a485b94d Mon Sep 17 00:00:00 2001 From: Aastha Gadhvi Date: Mon, 15 Jul 2024 15:55:43 +0530 Subject: [PATCH 1/3] 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 2/3] 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 b99f3fdd48934da5b8ddf78823e97e7ed7770bb0 Mon Sep 17 00:00:00 2001 From: Aastha Gadhvi Date: Fri, 19 Jul 2024 11:21:12 +0530 Subject: [PATCH 3/3] 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