diff --git a/lib/blocs/auth_bloc/auth_bloc.dart b/lib/blocs/auth_bloc/auth_bloc.dart index 1f7df10..eb3a831 100644 --- a/lib/blocs/auth_bloc/auth_bloc.dart +++ b/lib/blocs/auth_bloc/auth_bloc.dart @@ -13,6 +13,7 @@ class AuthBloc extends Bloc { super(AuthStateInitial()) { on(_onAuthEventLoginOAuth); on(_onAuthEventVerifyOAuth); + on(_onAuthEventAddEmailAndPassword); } void _onAuthEventLoginOAuth( @@ -46,4 +47,14 @@ class AuthBloc extends Bloc { emit(const AuthStateFailure()); } } + + void _onAuthEventAddEmailAndPassword( + AuthEventAddEmailAndPassword event, Emitter emit) async { + emit(AuthStateProcess()); + try { + await _userRepository.addEmailAndPassword(event.email, event.password); + } catch (e) { + emit(const AuthStateFailure()); + } + } } diff --git a/lib/blocs/auth_bloc/auth_event.dart b/lib/blocs/auth_bloc/auth_event.dart index 3afb717..72e4559 100644 --- a/lib/blocs/auth_bloc/auth_event.dart +++ b/lib/blocs/auth_bloc/auth_event.dart @@ -18,3 +18,16 @@ class AuthEventVerifyOAuth extends AuthEvent { const AuthEventVerifyOAuth({required this.code}); } + +class AuthEventAddEmailAndPassword extends AuthEvent { + final String email; + final String password; + + const AuthEventAddEmailAndPassword({ + required this.email, + required this.password, + }); + + @override + List get props => [email, password]; +} diff --git a/lib/blocs/profile_bloc/profile_bloc.dart b/lib/blocs/profile_bloc/profile_bloc.dart index 85744b7..641e08d 100644 --- a/lib/blocs/profile_bloc/profile_bloc.dart +++ b/lib/blocs/profile_bloc/profile_bloc.dart @@ -1,5 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart'; import 'package:user_repository/user_repository.dart'; part 'profile_event.dart'; @@ -7,25 +8,17 @@ part 'profile_state.dart'; class ProfileBloc extends Bloc { final UserRepository _userRepository; + // final AuthBloc _authBloc; // lo nuevo - ProfileBloc({required UserRepository userRepository}) - : _userRepository = userRepository, + ProfileBloc({ + required UserRepository userRepository, + // required AuthBloc authBloc + }) : _userRepository = userRepository, + // _authBloc = authBloc, super(UpdateUserInfoInitial()) { - // on(_onUploadPicture); on(_onUpdateUserInfo); } - // void _onUploadPicture(UploadPicture event, Emitter emit) async { - // emit(UploadPictureLoading()); - // try { - // String userImage = - // await _userRepository.uploadPicture(event.file, event.userId); - // emit(UploadPictureSuccess(userImage)); - // } catch (e) { - // emit(UploadPictureFailure()); - // } - // } - void _onUpdateUserInfo( UpdateUserInfo event, Emitter emit) async { emit(UpdateUserInfoLoading()); diff --git a/lib/components/gender_dropdown.dart b/lib/components/gender_dropdown.dart index 70f0574..2ed2563 100644 --- a/lib/components/gender_dropdown.dart +++ b/lib/components/gender_dropdown.dart @@ -34,7 +34,7 @@ class _GenderDropdownState extends State { child: DropdownButtonHideUnderline( child: DropdownButton( isExpanded: true, - value: controller.text, + value: controller.text == '' ? null : controller.text, hint: const Text( 'Selecciona tu género', style: TextStyle(fontSize: 16.0), diff --git a/lib/components/general_checkbox.dart b/lib/components/general_checkbox.dart new file mode 100644 index 0000000..a4fa982 --- /dev/null +++ b/lib/components/general_checkbox.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +class GeneralCheckbox extends StatelessWidget { + final String text; + final bool initialValue; + final Function(bool) onChanged; + + const GeneralCheckbox({ + super.key, + required this.text, + required this.initialValue, + required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return CheckboxListTile( + title: Text( + text, + style: const TextStyle(fontSize: 15), + ), + value: initialValue, + onChanged: (value) { + onChanged(value!); + }, + ); + } +} diff --git a/lib/components/general_primary_button.dart b/lib/components/general_primary_button.dart index e7f8ab4..4380287 100644 --- a/lib/components/general_primary_button.dart +++ b/lib/components/general_primary_button.dart @@ -1,10 +1,40 @@ import 'package:flutter/material.dart'; class GeneralPrimaryButton extends StatelessWidget { - const GeneralPrimaryButton({super.key}); + final VoidCallback onPressed; + final String label; + final bool isEnabled; + + const GeneralPrimaryButton({ + super.key, + required this.onPressed, + required this.label, + this.isEnabled = true, + }); @override Widget build(BuildContext context) { - return Container(); + return ElevatedButton( + onPressed: isEnabled ? onPressed : null, + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.primary, + elevation: 0, + minimumSize: Size( + MediaQuery.of(context).size.width * 0.5, + 50, + ), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(50)), + ), + ), + child: Text( + label, + style: TextStyle( + color: isEnabled ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ); } } diff --git a/lib/screens/authentication/sign_in_screen.dart b/lib/screens/authentication/sign_in_screen.dart index 87dd311..4f13711 100644 --- a/lib/screens/authentication/sign_in_screen.dart +++ b/lib/screens/authentication/sign_in_screen.dart @@ -24,6 +24,7 @@ class _SignInScreenState extends State { @override Widget build(BuildContext context) { + final width = MediaQuery.of(context).size.width; return BlocListener( listener: (context, state) { if (state is SignInSuccess) { @@ -41,103 +42,133 @@ class _SignInScreenState extends State { }); } }, - child: Form( - key: _formKey, - child: Column( - children: [ - const SizedBox(height: 20), - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: MyTextField( - controller: emailController, - hintText: 'Email', - obscureText: false, - keyboardType: TextInputType.emailAddress, - prefixIcon: Icon( - CupertinoIcons.mail_solid, - color: Colors.grey[600], - ), + child: Column( + children: [ + SizedBox( + width: double.infinity, + child: Row( + children: [ + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + CupertinoIcons.arrow_left, + size: 30, + ), + ), + Text( + 'Iniciar sesión', + style: TextStyle( + // fontSize: 30, + fontSize: width * 0.08, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + Form( + key: _formKey, + child: Column( + children: [ + const SizedBox(height: 20), + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: MyTextField( + controller: emailController, + hintText: 'Email', + obscureText: false, + keyboardType: TextInputType.emailAddress, + prefixIcon: Icon( + CupertinoIcons.mail_solid, + color: Colors.grey[600], + ), + errorMsg: _errorMsg, + validator: (val) { + if (val!.isEmpty) { + return 'Please fill in this field'; + } else if (!emailRexExp.hasMatch(val)) { + return 'Please enter a valid email'; + } + return null; + }), + ), + const SizedBox(height: 10), + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: MyTextField( + controller: passwordController, + hintText: 'Password', + obscureText: obscurePassword, + keyboardType: TextInputType.visiblePassword, + prefixIcon: + Icon(CupertinoIcons.lock_fill, color: Colors.grey[600]), errorMsg: _errorMsg, validator: (val) { if (val!.isEmpty) { return 'Please fill in this field'; - } else if (!emailRexExp.hasMatch(val)) { - return 'Please enter a valid email'; + } else if (!passwordRexExp.hasMatch(val)) { + return 'Please enter a valid password'; } return null; - }), - ), - const SizedBox(height: 10), - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: MyTextField( - controller: passwordController, - hintText: 'Password', - obscureText: obscurePassword, - keyboardType: TextInputType.visiblePassword, - prefixIcon: - Icon(CupertinoIcons.lock_fill, color: Colors.grey[600]), - errorMsg: _errorMsg, - validator: (val) { - if (val!.isEmpty) { - return 'Please fill in this field'; - } else if (!passwordRexExp.hasMatch(val)) { - return 'Please enter a valid password'; - } - return null; - }, - suffixIcon: IconButton( - onPressed: () { - setState(() { - obscurePassword = !obscurePassword; - if (obscurePassword) { - iconPassword = CupertinoIcons.eye_fill; - } else { - iconPassword = CupertinoIcons.eye_slash_fill; - } - }); }, - icon: Icon(iconPassword, color: Colors.grey[600]), + suffixIcon: IconButton( + onPressed: () { + setState(() { + obscurePassword = !obscurePassword; + if (obscurePassword) { + iconPassword = CupertinoIcons.eye_fill; + } else { + iconPassword = CupertinoIcons.eye_slash_fill; + } + }); + }, + icon: Icon(iconPassword, color: Colors.grey[600]), + ), ), ), - ), - const SizedBox(height: 20), - !signInRequired - ? SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - height: 50, - child: TextButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - context.read().add(SignInRequired( - emailController.text, passwordController.text)); - } - }, - style: TextButton.styleFrom( - elevation: 3.0, - backgroundColor: - Theme.of(context).colorScheme.primary, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(60))), - child: const Padding( - padding: - EdgeInsets.symmetric(horizontal: 25, vertical: 5), - child: Text( - 'Iniciar Sesión', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, + const SizedBox(height: 20), + !signInRequired + ? SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + height: 50, + child: TextButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + context.read().add(SignInRequired( + emailController.text, + passwordController.text)); + } + }, + style: TextButton.styleFrom( + elevation: 3.0, + backgroundColor: + Theme.of(context).colorScheme.primary, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(60))), + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 25, vertical: 5), + child: Text( + 'Iniciar Sesión', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w600, + ), ), ), ), - ), - ) - : const CircularProgressIndicator() - ], - )), + ) + : const CircularProgressIndicator() + ], + ), + ), + ], + ), ); } } diff --git a/lib/screens/authentication/sign_screen.dart b/lib/screens/authentication/sign_screen.dart index 099036e..a33cd2f 100644 --- a/lib/screens/authentication/sign_screen.dart +++ b/lib/screens/authentication/sign_screen.dart @@ -32,89 +32,116 @@ class _SignScreenState extends State with TickerProviderStateMixin { Widget build(BuildContext context) { double width = MediaQuery.of(context).size.width; return BlocListener( - listener: (context, state) { - if (state.status == AuthenticationStatus.authenticated) { - Navigator.pop(context); - } - }, - child: Scaffold( - appBar: AppBar( + listener: (context, state) { + if (state.status == AuthenticationStatus.authenticated) { + Navigator.pop(context); + } + }, + child: Scaffold( backgroundColor: Theme.of(context).colorScheme.tertiary, - ), - body: Column( - children: [ - // Text('${context.read().state}'), - Container( - color: Theme.of(context).colorScheme.tertiary, - child: Column( - children: [ - Container( - color: Theme.of(context).colorScheme.tertiary, - padding: const EdgeInsets.only(bottom: 20.0), - child: Center( - child: Image( - width: width * 0.7, - image: const AssetImage('images/logo_prosapp.png'), - ), - ), - ), - // TabBar( - // controller: tabController, - // unselectedLabelColor: - // Theme.of(context).colorScheme.onBackground, - // labelColor: Theme.of(context).colorScheme.onBackground, - // tabs: const [ - // Padding( - // padding: EdgeInsets.all(12.0), - // child: Text( - // 'Inicia sesión', - // style: TextStyle( - // fontSize: 18, - // ), - // ), - // ), - // Padding( - // padding: EdgeInsets.all(12.0), - // child: Text( - // 'Registrate', - // style: TextStyle( - // fontSize: 18, - // ), - // ), - // ), - // ], - // ), - ], - ), - ), - Expanded( - child: SingleChildScrollView( - child: SizedBox( - height: MediaQuery.of(context).size.height, - child: Column( - children: [ - Expanded( - child: TabBarView(controller: tabController, children: [ - BlocProvider( - create: (context) => - Injector.appInstance.get(), - child: SignInScreen(), - ), - BlocProvider( - create: (context) => - Injector.appInstance.get(), - child: SignUpScreen(), - ), - ]), - ) - ], + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Center( + child: Image( + width: width * 0.7, + image: const AssetImage('images/logo_prosapp.png'), ), ), ), - ), - ], - ), - ), - ); + Expanded( + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(60), + topRight: Radius.circular(60), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 30, vertical: 15), + child: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height - 200, + child: TabBarView( + controller: tabController, + children: [ + BlocProvider( + create: (context) => + Injector.appInstance.get(), + child: SignInScreen(), + ), + BlocProvider( + create: (context) => + Injector.appInstance.get(), + child: SignUpScreen(), + ), + ], + ), + ), + ), + ), + ), + ) + ], + ), + ) + + // Scaffold( + // // appBar: AppBar( + // // backgroundColor: Theme.of(context).colorScheme.tertiary, + // // ), + // body: Column( + // children: [ + // // Text('${context.read().state}'), + // Container( + // color: Theme.of(context).colorScheme.tertiary, + // child: Column( + // children: [ + // Container( + // color: Theme.of(context).colorScheme.tertiary, + // padding: const EdgeInsets.only(bottom: 20.0), + // child: Center( + // child: Image( + // width: width * 0.7, + // image: const AssetImage('images/logo_prosapp.png'), + // ), + // ), + // ), + // ], + // ), + // ), + // Expanded( + // child: SingleChildScrollView( + // child: SizedBox( + // height: MediaQuery.of(context).size.height, + // child: Column( + // children: [ + // Expanded( + // child: TabBarView(controller: tabController, children: [ + // BlocProvider( + // create: (context) => + // Injector.appInstance.get(), + // child: SignInScreen(), + // ), + // BlocProvider( + // create: (context) => + // Injector.appInstance.get(), + // child: SignUpScreen(), + // ), + // ]), + // ) + // ], + // ), + // ), + // ), + // ), + // ], + // ), + // ), + ); } } diff --git a/lib/screens/authentication/sign_up_screen.dart b/lib/screens/authentication/sign_up_screen.dart index 06605cd..2004305 100644 --- a/lib/screens/authentication/sign_up_screen.dart +++ b/lib/screens/authentication/sign_up_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:prosappco/components/general_primary_button.dart'; import 'package:user_repository/user_repository.dart'; import '../../blocs/sign_up_bloc/sign_up_bloc.dart'; @@ -31,6 +32,8 @@ class _SignUpScreenState extends State { @override Widget build(BuildContext context) { + final width = MediaQuery.of(context).size.width; + return BlocListener( listener: (context, state) { if (state is SignUpSuccess) { @@ -45,178 +48,212 @@ class _SignUpScreenState extends State { return; } }, - child: Scaffold( - body: Form( - key: _formKey, - child: Center( - child: Column( + child: Column( + children: [ + SizedBox( + width: double.infinity, + child: Row( children: [ - const SizedBox(height: 20), - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: MyTextField( - controller: emailController, - hintText: 'Email', - obscureText: false, - keyboardType: TextInputType.emailAddress, - prefixIcon: const Icon(CupertinoIcons.mail_solid), - validator: (val) { - if (val!.isEmpty) { - return 'Please fill in this field'; - } else if (!emailRexExp.hasMatch(val)) { - return 'Please enter a valid email'; - } - return null; - }), + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + CupertinoIcons.arrow_left, + size: 30, + ), ), - const SizedBox(height: 10), - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: MyTextField( - controller: passwordController, - hintText: 'Password', - obscureText: obscurePassword, - keyboardType: TextInputType.visiblePassword, - prefixIcon: const Icon(CupertinoIcons.lock_fill), - onChanged: (val) { - if (val!.contains(RegExp(r'[A-Z]'))) { - setState(() { - containsUpperCase = true; - }); - } else { - setState(() { - containsUpperCase = false; - }); - } - if (val.contains(RegExp(r'[a-z]'))) { - setState(() { - containsLowerCase = true; - }); - } else { - setState(() { - containsLowerCase = false; - }); - } - if (val.contains(RegExp(r'[0-9]'))) { - setState(() { - containsNumber = true; - }); - } else { - setState(() { - containsNumber = false; - }); - } - if (val.contains(specialCharRexExp)) { - setState(() { - containsSpecialChar = true; - }); - } else { - setState(() { - containsSpecialChar = false; - }); - } - if (val.length >= 8) { - setState(() { - contains8Length = true; - }); - } else { - setState(() { - contains8Length = false; - }); - } - return null; - }, - suffixIcon: IconButton( - onPressed: () { - setState(() { - obscurePassword = !obscurePassword; - if (obscurePassword) { - iconPassword = CupertinoIcons.eye_fill; - } else { - iconPassword = CupertinoIcons.eye_slash_fill; - } - }); + Text( + 'Registrate', + style: TextStyle( + // fontSize: 30, + fontSize: width * 0.08, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + Form( + key: _formKey, + child: Center( + child: Column( + children: [ + const SizedBox(height: 20), + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: MyTextField( + controller: emailController, + hintText: 'Email', + obscureText: false, + keyboardType: TextInputType.emailAddress, + prefixIcon: const Icon(CupertinoIcons.mail_solid), + validator: (val) { + if (val!.isEmpty) { + return 'Please fill in this field'; + } else if (!emailRexExp.hasMatch(val)) { + return 'Please enter a valid email'; + } + return null; + }), + ), + const SizedBox(height: 10), + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: MyTextField( + controller: passwordController, + hintText: 'Password', + obscureText: obscurePassword, + keyboardType: TextInputType.visiblePassword, + prefixIcon: const Icon(CupertinoIcons.lock_fill), + onChanged: (val) { + if (val!.contains(RegExp(r'[A-Z]'))) { + setState(() { + containsUpperCase = true; + }); + } else { + setState(() { + containsUpperCase = false; + }); + } + if (val.contains(RegExp(r'[a-z]'))) { + setState(() { + containsLowerCase = true; + }); + } else { + setState(() { + containsLowerCase = false; + }); + } + if (val.contains(RegExp(r'[0-9]'))) { + setState(() { + containsNumber = true; + }); + } else { + setState(() { + containsNumber = false; + }); + } + if (val.contains(specialCharRexExp)) { + setState(() { + containsSpecialChar = true; + }); + } else { + setState(() { + containsSpecialChar = false; + }); + } + if (val.length >= 8) { + setState(() { + contains8Length = true; + }); + } else { + setState(() { + contains8Length = false; + }); + } + return null; }, - icon: Icon(iconPassword), + suffixIcon: IconButton( + onPressed: () { + setState(() { + obscurePassword = !obscurePassword; + if (obscurePassword) { + iconPassword = CupertinoIcons.eye_fill; + } else { + iconPassword = CupertinoIcons.eye_slash_fill; + } + }); + }, + icon: Icon(iconPassword), + ), + validator: (val) { + if (val!.isEmpty) { + return 'Please fill in this field'; + } else if (!passwordRexExp.hasMatch(val)) { + return 'Please enter a valid password'; + } + return null; + }), + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "⚈ 1 uppercase", + style: TextStyle( + color: containsUpperCase + ? Colors.green + : Theme.of(context) + .colorScheme + .onBackground), + ), + Text( + "⚈ 1 lowercase", + style: TextStyle( + color: containsLowerCase + ? Colors.green + : Theme.of(context) + .colorScheme + .onBackground), + ), + ], ), - validator: (val) { - if (val!.isEmpty) { - return 'Please fill in this field'; - } else if (!passwordRexExp.hasMatch(val)) { - return 'Please enter a valid password'; - } - return null; - }), - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "⚈ 1 uppercase", - style: TextStyle( - color: containsUpperCase - ? Colors.green - : Theme.of(context).colorScheme.onBackground), - ), - Text( - "⚈ 1 lowercase", - style: TextStyle( - color: containsLowerCase - ? Colors.green - : Theme.of(context).colorScheme.onBackground), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "⚈ 8 minimum character", - style: TextStyle( - color: contains8Length - ? Colors.green - : Theme.of(context).colorScheme.onBackground), - ), - Text( - "⚈ 1 number", - style: TextStyle( - color: containsNumber - ? Colors.green - : Theme.of(context).colorScheme.onBackground), - ), - ], - ), - ], - ), - const SizedBox(height: 10), - SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: MyTextField( - labelText: 'Nombre', - controller: nameController, - hintText: 'Ingresa tu nombre', - obscureText: false, - keyboardType: TextInputType.name, - prefixIcon: const Icon(CupertinoIcons.person_fill), - validator: (val) { - if (val!.isEmpty) { - return 'Please fill in this field'; - } else if (val.length > 30) { - return 'Name too long'; - } - return null; - }), - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.02), - !signUpRequired - ? SizedBox( - width: MediaQuery.of(context).size.width * 0.5, - child: TextButton( + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "⚈ 8 minimum character", + style: TextStyle( + color: contains8Length + ? Colors.green + : Theme.of(context) + .colorScheme + .onBackground), + ), + Text( + "⚈ 1 number", + style: TextStyle( + color: containsNumber + ? Colors.green + : Theme.of(context) + .colorScheme + .onBackground), + ), + ], + ), + ], + ), + const SizedBox(height: 10), + SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: MyTextField( + labelText: 'Nombre', + controller: nameController, + hintText: 'Ingresa tu nombre', + obscureText: false, + keyboardType: TextInputType.name, + prefixIcon: const Icon(CupertinoIcons.person_fill), + validator: (val) { + if (val!.isEmpty) { + return 'Please fill in this field'; + } else if (val.length > 30) { + return 'Name too long'; + } + return null; + }), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.02), + !signUpRequired + ? SizedBox( + width: MediaQuery.of(context).size.width * 0.5, + child: GeneralPrimaryButton( + label: 'Registrarme', onPressed: () { if (_formKey.currentState!.validate()) { MyUser myUser = MyUser.empty; @@ -231,31 +268,14 @@ class _SignUpScreenState extends State { }); } }, - style: TextButton.styleFrom( - elevation: 3.0, - backgroundColor: - Theme.of(context).colorScheme.primary, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(60))), - child: const Padding( - padding: EdgeInsets.symmetric( - horizontal: 25, vertical: 5), - child: Text( - 'Sign Up', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600), - ), - )), - ) - : const CircularProgressIndicator(), - ], + ), + ) + : const CircularProgressIndicator(), + ], + ), ), ), - ), + ], ), ); } diff --git a/lib/screens/authentication/welcome_screen.dart b/lib/screens/authentication/welcome_screen.dart index c3de2fb..6285eec 100644 --- a/lib/screens/authentication/welcome_screen.dart +++ b/lib/screens/authentication/welcome_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl_phone_field/intl_phone_field.dart'; import 'package:prosappco/components/general_input_decoration.dart'; +import 'package:prosappco/components/general_primary_button.dart'; import 'package:prosappco/screens/authentication/otp_auth_screen.dart'; import 'package:prosappco/screens/authentication/sign_screen.dart'; @@ -100,7 +101,7 @@ class WelcomeScreen extends StatelessWidget { color: Theme.of(context).colorScheme.onBackground, ), ), - ElevatedButton( + GeneralPrimaryButton( onPressed: () { final phoneNumber = _phoneNumber; @@ -112,10 +113,26 @@ class WelcomeScreen extends StatelessWidget { OtpAuthScreen(phoneNumber: phoneNumber), ), ); - } else {} + } }, - child: const Text('Enviar código'), + label: 'Enviar código', ), + // ElevatedButton( + // onPressed: () { + // final phoneNumber = _phoneNumber; + + // if (phoneNumber != null && phoneNumber.isNotEmpty) { + // Navigator.push( + // context, + // CupertinoPageRoute( + // builder: (context) => + // OtpAuthScreen(phoneNumber: phoneNumber), + // ), + // ); + // } else {} + // }, + // child: const Text('Enviar código'), + // ), TextButton( onPressed: () { Navigator.push( diff --git a/lib/screens/profile/components/profile_item.dart b/lib/screens/profile/components/profile_item.dart new file mode 100644 index 0000000..dc4b3bb --- /dev/null +++ b/lib/screens/profile/components/profile_item.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +class ProfileItem extends StatelessWidget { + final String title; + final String? subtitle; + final IconData? leading; + final VoidCallback onTap; + + const ProfileItem({ + super.key, + required this.title, + this.subtitle, + this.leading, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return Card( + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + color: Colors.grey.shade100, + child: ListTile( + title: Text( + title, + style: const TextStyle(color: Colors.black), + ), + subtitle: subtitle == null + ? null + : Text( + subtitle ?? '', + style: const TextStyle(color: Colors.black), + ), + leading: leading == null + ? null + : Icon( + leading, + color: Colors.black, + ), + trailing: const Icon( + Icons.keyboard_arrow_right, + color: Colors.black, + ), + onTap: onTap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + ), + ); + } +} diff --git a/lib/screens/profile/profile_email_screen.dart b/lib/screens/profile/profile_email_screen.dart new file mode 100644 index 0000000..ca09d06 --- /dev/null +++ b/lib/screens/profile/profile_email_screen.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart'; + +class ProfileEmailScreen extends StatefulWidget { + const ProfileEmailScreen({super.key}); + + @override + State createState() => _ProfileEmailScreenState(); +} + +class _ProfileEmailScreenState extends State { + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + + @override + void dispose() { + _emailController.dispose(); + _passwordController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state.status == MyUserStatus.success) { + _emailController.text = state.user!.email ?? ''; + + return Scaffold( + appBar: AppBar( + title: Text( + _emailController.text.isEmpty + ? 'Agregar correo' + : 'Actualizar correo', + ), + ), + body: Center( + // Centro del contenido + child: SingleChildScrollView( + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 40, vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + TextFormField( + controller: _emailController, + decoration: const InputDecoration( + labelText: 'Email', + prefixIcon: Icon(Icons.email_rounded), + hintText: 'Email', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(10.0), + )), + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.red), + ), + focusedErrorBorder: OutlineInputBorder( + borderSide: + BorderSide(color: Colors.red, width: 2.0), + ), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Por favor, ingrese su contraseña'; + } + return null; + }, + ), + const SizedBox(height: 20), + TextFormField( + controller: _passwordController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Contraseña', + prefixIcon: Icon(Icons.lock_rounded), + hintText: 'Contraseña', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(10.0), + )), + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.red), + ), + focusedErrorBorder: OutlineInputBorder( + borderSide: + BorderSide(color: Colors.red, width: 2.0), + ), + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Por favor, ingrese su contraseña'; + } + return null; + }, + ), + const SizedBox(height: 30), + ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + padding: const EdgeInsets.symmetric(vertical: 5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + shadowColor: Colors.grey, + elevation: 5, + ), + child: Container( + constraints: const BoxConstraints( + maxWidth: 300.0, minHeight: 50.0), + alignment: Alignment.center, + child: const Text( + 'Actualizar', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ); + } +} diff --git a/lib/screens/profile/profile_phone_screen.dart b/lib/screens/profile/profile_phone_screen.dart new file mode 100644 index 0000000..8dd3f11 --- /dev/null +++ b/lib/screens/profile/profile_phone_screen.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart'; + +class ProfilePhoneScreen extends StatefulWidget { + const ProfilePhoneScreen({super.key}); + + @override + State createState() => _ProfilePhoneScreenState(); +} + +class _ProfilePhoneScreenState extends State { + final TextEditingController _phoneController = TextEditingController(); + + @override + void dispose() { + _phoneController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state.status == MyUserStatus.success) { + _phoneController.text = state.user!.phone ?? ''; + + return Scaffold( + appBar: AppBar( + title: Text( + _phoneController.text.isEmpty + ? 'Agregar telefono' + : 'Actualizar telefono', + ), + ), + body: const Placeholder(), + ); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ); + } +} diff --git a/lib/screens/profile/profile_screen.dart b/lib/screens/profile/profile_screen.dart index 318b4ed..7494692 100644 --- a/lib/screens/profile/profile_screen.dart +++ b/lib/screens/profile/profile_screen.dart @@ -1,14 +1,18 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:injector/injector.dart'; import 'package:intl/intl.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart'; import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart'; import 'package:prosappco/blocs/profile_bloc/profile_bloc.dart'; import 'package:prosappco/components/birthday_picker.dart'; import 'package:prosappco/components/gender_dropdown.dart'; -import 'package:prosappco/src/components/pop_appbar.dart'; +import 'package:prosappco/screens/profile/components/profile_item.dart'; +import 'package:prosappco/screens/profile/profile_email_screen.dart'; +import 'package:prosappco/screens/profile/profile_phone_screen.dart'; class ProfileScreen extends StatefulWidget { const ProfileScreen({super.key}); @@ -20,13 +24,19 @@ class ProfileScreen extends StatefulWidget { class _ProfileScreenState extends State { final TextEditingController _nameController = TextEditingController(); final TextEditingController _emailController = TextEditingController(); + final TextEditingController _newEmailController = TextEditingController(); final TextEditingController _phoneController = TextEditingController(); final TextEditingController _birthdayController = TextEditingController(); final TextEditingController _genderController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); XFile? _imageFile; bool isLoading = false; + bool enableLoginWithEmail = false; + bool obscurePassword = true; + IconData iconPassword = CupertinoIcons.eye_fill; + @override void dispose() { _nameController.dispose(); @@ -34,149 +44,356 @@ class _ProfileScreenState extends State { _phoneController.dispose(); _birthdayController.dispose(); _genderController.dispose(); + _passwordController.dispose(); + _newEmailController.dispose(); + super.dispose(); } @override Widget build(BuildContext context) { - return BlocListener( - listener: (context, state) { - if (state is UpdateUserInfoLoading) { - setState(() { - isLoading = true; - }); - } else if (state is UpdateUserInfoSuccess) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('Información actualizada'), - )); - setState(() { - isLoading = false; - }); - } else if (state is UpdateUserInfoFailure) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('Error al actualizar la información'), - )); - setState(() { - isLoading = false; - }); - } - }, - child: Scaffold( - appBar: PopAppbar( - onPressed: () { - Navigator.pop(context); - }, - label: 'Perfil', - ), - body: BlocBuilder( - builder: (context, state) { - if (state.status == MyUserStatus.success) { - _nameController.text = state.user!.name ?? ''; - _emailController.text = state.user!.email ?? ''; - _phoneController.text = state.user!.phone ?? ''; - _birthdayController.text = state.user!.birthday ?? ''; - _genderController.text = state.user!.gender ?? ''; + final authBloc = Injector.appInstance.get(); - return SingleChildScrollView( - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 40, vertical: 20), - child: Stack( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - pictureWidget(state, context), - const SizedBox(height: 20.0), - TextFormField( - controller: _nameController, - decoration: const InputDecoration( - labelText: 'Nombre', - prefixIcon: Icon(Icons.person), - hintText: 'Nombre (obligatorio)', - border: OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.circular(10.0), - )), - errorBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.red), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: - BorderSide(color: Colors.red, width: 2.0), - ), + return BlocProvider( + create: (context) => authBloc, + child: BlocListener( + listener: (context, state) { + if (state is UpdateUserInfoLoading) { + setState(() { + isLoading = true; + }); + } else if (state is UpdateUserInfoSuccess) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('Información actualizada'), + )); + setState(() { + isLoading = false; + }); + } else if (state is UpdateUserInfoFailure) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('Error al actualizar la información'), + )); + setState(() { + isLoading = false; + }); + } + }, + child: Scaffold( + appBar: AppBar( + title: const Text('Perfil'), + ), + body: BlocBuilder( + builder: (context, state) { + if (state.status == MyUserStatus.success) { + _nameController.text = state.user!.name ?? ''; + _emailController.text = state.user!.email ?? ''; + _phoneController.text = state.user!.phone ?? ''; + _birthdayController.text = state.user!.birthday ?? ''; + _genderController.text = state.user!.gender ?? ''; + + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 40, vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + pictureWidget(state, context), + const SizedBox(height: 30), + TextFormField( + controller: _nameController, + decoration: const InputDecoration( + labelText: 'Nombre', + prefixIcon: Icon(Icons.person), + hintText: 'Nombre (obligatorio)', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(10.0), + )), + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.red), ), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Por favor, ingrese su nombre'; - } - return null; - }, - ), - const SizedBox(height: 20.0), - TextFormField( - controller: _emailController, - decoration: const InputDecoration( - labelText: 'Email', - prefixIcon: Icon(Icons.email_rounded), - hintText: 'Email', - border: OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.circular(10.0), - )), - errorBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.red), - ), - focusedErrorBorder: OutlineInputBorder( - borderSide: - BorderSide(color: Colors.red, width: 2.0), - ), + focusedErrorBorder: OutlineInputBorder( + borderSide: + BorderSide(color: Colors.red, width: 2.0), ), ), - const SizedBox(height: 20.0), - TextFormField( - controller: _phoneController, - decoration: const InputDecoration( - labelText: 'Número de Teléfono', - prefixIcon: Icon(Icons.phone_android_rounded), - hintText: '+57', - border: OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.circular(10.0), - )), - errorBorder: OutlineInputBorder( - borderSide: BorderSide(color: Colors.red), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Por favor, ingrese su nombre'; + } + return null; + }, + ), + const SizedBox(height: 20), + ProfileItem( + title: 'Iniciar sesión con correo', + subtitle: _emailController.text, + leading: Icons.email_rounded, + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + const ProfileEmailScreen(), ), - focusedErrorBorder: OutlineInputBorder( - borderSide: - BorderSide(color: Colors.red, width: 2.0), + ); + }, + ), + const SizedBox(height: 20), + ProfileItem( + title: 'Iniciar sesión con teléfono', + subtitle: _phoneController.text, + leading: Icons.phone_iphone_rounded, + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + const ProfilePhoneScreen(), ), - ), - ), - const SizedBox(height: 20.0), - BirthdayPicker( - onDateSelected: (birthDay) { - _birthdayController.text = - DateFormat('dd/MM/yyyy').format(birthDay); - }, - controller: _birthdayController, - ), - const SizedBox(height: 20.0), - GenderDropdown( - controller: _genderController, - ), - const SizedBox(height: 60.0), - saveButton(state, context), - ], - ), - ], + ); + }, + ), + + // Column( + // children: [ + // const SizedBox(height: 20.0), + // TextFormField( + // readOnly: true, + // controller: _emailController, + // decoration: const InputDecoration( + // labelText: 'Email', + // prefixIcon: Icon(Icons.email_rounded), + // hintText: 'Email', + // border: OutlineInputBorder( + // borderRadius: BorderRadius.all( + // Radius.circular(10.0), + // )), + // errorBorder: OutlineInputBorder( + // borderSide: BorderSide(color: Colors.red), + // ), + // focusedErrorBorder: OutlineInputBorder( + // borderSide: BorderSide( + // color: Colors.red, width: 2.0), + // ), + // ), + // ), + // ], + // ), + // const SizedBox(height: 20.0), + // TextFormField( + // readOnly: true, + // controller: _phoneController, + // decoration: const InputDecoration( + // labelText: 'Número de Teléfono', + // prefixIcon: Icon(Icons.phone_android_rounded), + // hintText: '+57', + // border: OutlineInputBorder( + // borderRadius: BorderRadius.all( + // Radius.circular(10.0), + // )), + // errorBorder: OutlineInputBorder( + // borderSide: BorderSide(color: Colors.red), + // ), + // focusedErrorBorder: OutlineInputBorder( + // borderSide: + // BorderSide(color: Colors.red, width: 2.0), + // ), + // ), + // ), + // _emailController.text.isEmpty + // ? Column( + // children: [ + // const SizedBox(height: 20.0), + // GeneralCheckbox( + // text: + // 'Habilitar inicio de sesión con correo (Opcional)', + // initialValue: enableLoginWithEmail, + // onChanged: (value) { + // setState(() { + // enableLoginWithEmail = value; + // }); + // }, + // ), + // enableLoginWithEmail + // ? Container( + // decoration: BoxDecoration( + // border: Border.all( + // color: Colors.blue, + // width: 0.5, + // ), + // borderRadius: + // BorderRadius.circular(10), + // ), + // padding: const EdgeInsets.all(10), + // child: Column( + // children: [ + // TextFormField( + // controller: + // _newEmailController, + // validator: (String? value) { + // if (enableLoginWithEmail) { + // if (value == null || + // value.isEmpty) { + // return 'Por favor ingrese un email'; + // } + // final RegExp + // emailRegExp = + // RegExp( + // r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); + // if (!emailRegExp + // .hasMatch(value)) { + // return 'Por favor ingrese un email válido'; + // } + // return null; + // } else { + // return null; + // } + // }, + // decoration: + // const InputDecoration( + // prefixIcon: Icon( + // Icons.email_rounded), + // hintText: 'Email', + // ), + // ), + // const SizedBox(height: 20.0), + // TextFormField( + // controller: + // _passwordController, + // obscureText: + // obscurePassword, + // validator: (value) { + // if (enableLoginWithEmail) { + // if (value == null || + // value.isEmpty) { + // return 'Por favor ingrese una contraseña.'; + // } + // if (value.length < 5) { + // return 'Debe tener al menos 5 caracteres.'; + // } + // return null; + // } else { + // return null; + // } + // }, + // decoration: InputDecoration( + // prefixIcon: const Icon( + // Icons.lock_rounded), + // suffixIcon: IconButton( + // onPressed: () { + // setState(() { + // obscurePassword = + // !obscurePassword; + // if (obscurePassword) { + // iconPassword = + // CupertinoIcons + // .eye_fill; + // } else { + // iconPassword = + // CupertinoIcons + // .eye_slash_fill; + // } + // }); + // }, + // icon: Icon(iconPassword, + // color: Colors + // .grey[600]), + // ), + // hintText: 'Contraseña', + // ), + // ), + // const SizedBox(height: 20), + // Container( + // margin: + // const EdgeInsets.only( + // left: 5, + // right: 5, + // top: 5, + // bottom: 5, + // ), + // padding: const EdgeInsets + // .symmetric( + // horizontal: 10, + // vertical: 8, + // ), + // decoration: BoxDecoration( + // color: const Color( + // 0xFFD6F4FF), + // borderRadius: + // BorderRadius.circular( + // 20), + // boxShadow: [ + // BoxShadow( + // color: Colors.grey + // .withOpacity(0.5), + // spreadRadius: 1, + // blurRadius: 5, + // offset: const Offset( + // 1, 3), + // ), + // ], + // ), + // child: const Row( + // children: [ + // Icon( + // Icons.error_outline, + // size: 20, + // color: Colors.black54, + // ), + // SizedBox(width: 10), + // Expanded( + // child: Text( + // 'Al habilitar el inicio de sesión con correo, se cerrara la sesión actual.', + // style: TextStyle( + // color: Colors + // .black54, + // fontSize: 13, + // ), + // ), + // ), + // ], + // ), + // ) + // ], + // ), + // ) + // : const SizedBox(), + // ], + // ) + // : const SizedBox(), + _birthdayController.text.isEmpty && + _genderController.text.isEmpty + ? Column( + children: [ + const SizedBox(height: 20.0), + BirthdayPicker( + onDateSelected: (birthDay) { + _birthdayController.text = + DateFormat('dd/MM/yyyy') + .format(birthDay); + }, + controller: _birthdayController, + ), + const SizedBox(height: 20.0), + GenderDropdown( + controller: _genderController, + ), + ], + ) + : const SizedBox(), + const SizedBox(height: 60.0), + saveButton(state, context), + ], + ), ), - ), - ); - } else { - return const Center(child: CircularProgressIndicator()); - } - }, + ); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ), ), ), ); @@ -189,6 +406,25 @@ class _ProfileScreenState extends State { return; } + if (enableLoginWithEmail) { + if (_newEmailController.text.isEmpty) { + return; + } + + if (_passwordController.text.isEmpty) { + return; + } + + context.read().add( + AuthEventAddEmailAndPassword( + email: _newEmailController.text, + password: _passwordController.text, + ), + ); + + _emailController.text = _newEmailController.text; + } + final myUser = state.user!.copyWith( name: _nameController.text, email: _emailController.text, @@ -209,7 +445,7 @@ class _ProfileScreenState extends State { }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, - padding: const EdgeInsets.symmetric(vertical: 15), + padding: const EdgeInsets.symmetric(vertical: 5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), diff --git a/lib/src/presentation/screens/profile/profile.dart b/lib/src/presentation/screens/profile/profile.dart index aa7e952..220142d 100644 --- a/lib/src/presentation/screens/profile/profile.dart +++ b/lib/src/presentation/screens/profile/profile.dart @@ -374,6 +374,25 @@ class _ProfileScreenState extends State { ); } + Future updateEmailAndPassword(String email, String password) async { + final User? user = FirebaseAuth.instance.currentUser; + if (user != null) { + try { + await user.updateEmail(email); + await user.updatePassword(password); + + return true; + } catch (e) { + WarningSnackbar.show( + title: 'Inicia sesión de nuevo', + message: 'Inicia la sesión de nuevo para guardar los cambios.', + ); + AuthenticationRepository.instance.logout(uid!); + } + } + return false; + } + Future _updateEmailAndPassword( String newEmail, String currentPassword) async { final user = _auth.currentUser; @@ -502,24 +521,7 @@ class _ProfileScreenState extends State { ); } - Future updateEmailAndPassword(String email, String password) async { - final User? user = FirebaseAuth.instance.currentUser; - if (user != null) { - try { - await user.updateEmail(email); - await user.updatePassword(password); - return true; - } catch (e) { - WarningSnackbar.show( - title: 'Inicia sesión de nuevo', - message: 'Inicia la sesión de nuevo para guardar los cambios.', - ); - AuthenticationRepository.instance.logout(uid!); - } - } - return false; - } bool enableLoginWithEmail = false; diff --git a/packages/user_repository/lib/src/repositories/firebase_user_repository.dart b/packages/user_repository/lib/src/repositories/firebase_user_repository.dart index d8aac43..2b3e792 100644 --- a/packages/user_repository/lib/src/repositories/firebase_user_repository.dart +++ b/packages/user_repository/lib/src/repositories/firebase_user_repository.dart @@ -164,6 +164,25 @@ class FirebaseUserRepository implements UserRepository { } } + // Add email and password to user authenticate with phone + @override + Future addEmailAndPassword(String email, String password) async { + try { + await _firebaseAuth.currentUser!.updateEmail(email); + await _firebaseAuth.currentUser!.updatePassword(password); + + return true; + } catch (e) { + log('xd -- Error add email and password ${e.toString()}'); + + if (e is FirebaseAuthException && e.code == 'requires-recent-login') {} + + if (e is FirebaseAuthException && e.code == 'email-already-in-use') {} + + return false; + } + } + // Sign out @override Future logOut() async { diff --git a/packages/user_repository/lib/src/repositories/user_repo.dart b/packages/user_repository/lib/src/repositories/user_repo.dart index f4f256a..5788a7b 100644 --- a/packages/user_repository/lib/src/repositories/user_repo.dart +++ b/packages/user_repository/lib/src/repositories/user_repo.dart @@ -7,6 +7,8 @@ abstract class UserRepository { Future signIn(String email, String password); + Future addEmailAndPassword(String email, String password); + Future logOut(); // Future signUp(String name, String email, String password);