diff --git a/lib/main.dart b/lib/main.dart index 0aaf022..0818ea0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,20 +1,9 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:prosappco/src/authentication/authentication_repository.dart'; -import 'package:prosappco/src/provider/google_sign.dart'; import 'package:prosappco/src/screens/login.dart'; import 'package:firebase_core/firebase_core.dart'; -import 'package:provider/provider.dart'; -import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart'; -import 'package:prosappco/src/provider/google_sign.dart'; -import 'package:prosappco/src/screens/login.dart'; -import 'package:prosappco/src/screens/welcome.dart'; -import 'package:provider/provider.dart'; - -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:prosappco/src/screens/register.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -24,22 +13,6 @@ void main() async { runApp(const MyApp()); } -final FirebaseAuth _auth = FirebaseAuth.instance; -final GoogleSignIn googleSignIn = GoogleSignIn(); - -Future signInWithGoogle() async { - final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn(); - final GoogleSignInAuthentication googleSignInAuthentication = - await googleSignInAccount!.authentication; - - final AuthCredential credential = GoogleAuthProvider.credential( - accessToken: googleSignInAuthentication.accessToken, - idToken: googleSignInAuthentication.idToken, - ); - - return await _auth.signInWithCredential(credential); -} - class MyApp extends StatelessWidget { const MyApp({super.key}); diff --git a/lib/src/authentication/authentication_repository.dart b/lib/src/authentication/authentication_repository.dart index eaddc4b..d77d266 100644 --- a/lib/src/authentication/authentication_repository.dart +++ b/lib/src/authentication/authentication_repository.dart @@ -1,5 +1,3 @@ -import 'dart:ffi'; - import 'package:firebase_auth/firebase_auth.dart'; import 'package:get/get.dart'; import 'package:google_sign_in/google_sign_in.dart'; @@ -14,10 +12,11 @@ class AuthenticationRepository extends GetxController { final _auth = FirebaseAuth.instance; late final Rx firebaseUser; final GoogleSignIn googleSignIn = GoogleSignIn(); + var verificationId = ''.obs; @override void onReady() { - Future.delayed(const Duration(seconds: 6)); + // Future.delayed(const Duration(seconds: 6)); firebaseUser = Rx(_auth.currentUser); firebaseUser.bindStream(_auth.userChanges()); ever(firebaseUser, _setInitialScreen); @@ -29,6 +28,35 @@ class AuthenticationRepository extends GetxController { : Get.offAll(() => const WelcomeScreen()); } + Future phoneAuthentication(String phoneNo) async { + await _auth.verifyPhoneNumber( + phoneNumber: phoneNo, + verificationCompleted: (credential) async { + await _auth.signInWithCredential(credential); + }, + codeSent: (verificationId, resendToken) { + this.verificationId.value = verificationId; + }, + codeAutoRetrievalTimeout: (verificationId) { + this.verificationId.value = verificationId; + }, + verificationFailed: (e) { + if (e.code == 'invalid-phone-number') { + Get.snackbar('Error', 'El numero no es valido.'); + } else { + Get.snackbar('Error', 'Algo ha ido mal. Inténtalo de nuevo. $e'); + } + }, + ); + } + + Future verifyOTP(String otp) async { + var credentials = await _auth.signInWithCredential( + PhoneAuthProvider.credential( + verificationId: verificationId.value, smsCode: otp)); + return credentials.user != null ? true : false; + } + Future createUserWithEmailAndPassword( String email, String password) async { try { @@ -54,17 +82,20 @@ class AuthenticationRepository extends GetxController { } catch (_) {} } - Future signInWithGoogle() async { - final GoogleSignInAccount? googleSignInAccount = - await googleSignIn.signIn(); - final GoogleSignInAuthentication googleSignInAuthentication = - await googleSignInAccount!.authentication; - - final AuthCredential credential = GoogleAuthProvider.credential( - accessToken: googleSignInAuthentication.accessToken, - idToken: googleSignInAuthentication.idToken, - ); - - return await _auth.signInWithCredential(credential); + Future signInWithGoogle() async { + try { + final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn(); + final GoogleSignInAuthentication googleAuth = + await googleUser!.authentication; + final credential = GoogleAuthProvider.credential( + accessToken: googleAuth.accessToken, + idToken: googleAuth.idToken, + ); + await FirebaseAuth.instance.signInWithCredential(credential); + } catch (e) { + print('Error - ${e}'); + } } + + Future logout() async => _auth.signOut(); } diff --git a/lib/src/controllers/otp_controller.dart b/lib/src/controllers/otp_controller.dart new file mode 100644 index 0000000..12d7cf6 --- /dev/null +++ b/lib/src/controllers/otp_controller.dart @@ -0,0 +1,12 @@ +import 'package:get/get.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/screens/welcome.dart'; + +class OTPController extends GetxController { + static OTPController get instance => Get.find(); + + Future verifyOTP(String otp) async { + var isVerified = AuthenticationRepository.instance.verifyOTP(otp); + await isVerified ? Get.offAll(const WelcomeScreen()) : Get.back(); + } +} diff --git a/lib/src/controllers/phone_auth_controller.dart b/lib/src/controllers/phone_auth_controller.dart new file mode 100644 index 0000000..e1972cd --- /dev/null +++ b/lib/src/controllers/phone_auth_controller.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; + +class PhoneAuthController extends GetxController { + static PhoneAuthController get instance => Get.find(); + + final phoneNo = TextEditingController(); + + void phoneAuthentication(String phoneNo) { + AuthenticationRepository.instance.phoneAuthentication(phoneNo); + } +} diff --git a/lib/src/controllers/register_controller.dart b/lib/src/controllers/register_controller.dart index 3f09b83..55d91a6 100644 --- a/lib/src/controllers/register_controller.dart +++ b/lib/src/controllers/register_controller.dart @@ -5,7 +5,6 @@ import 'package:prosappco/src/authentication/authentication_repository.dart'; class RegisterController extends GetxController { static RegisterController get instance => Get.find(); - // textField controllers to get data from textfields final name = TextEditingController(); final email = TextEditingController(); final password = TextEditingController(); diff --git a/lib/src/provider/google_sign.dart b/lib/src/provider/google_sign.dart deleted file mode 100644 index 43e7cf3..0000000 --- a/lib/src/provider/google_sign.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:flutter/material.dart'; -import 'package:firebase_auth/firebase_auth.dart'; -import 'package:google_sign_in/google_sign_in.dart'; - -class GoogleSignProvider extends ChangeNotifier { - final googleSign = GoogleSignIn(); - - GoogleSignInAccount? _user; - - GoogleSignInAccount get user => _user!; - - Future googleLogin() async { - final googleUser = await googleSign.signIn(); - if (googleUser == null) return; - _user = googleUser; - - final googleAuth = await googleUser.authentication; - - final credential = GoogleAuthProvider.credential( - accessToken: googleAuth.accessToken, idToken: googleAuth.idToken); - - await FirebaseAuth.instance.signInWithCredential(credential); - - notifyListeners(); - } -} diff --git a/lib/src/screens/code_validation.dart b/lib/src/screens/code_validation.dart index 9ad294f..6f0b9e9 100644 --- a/lib/src/screens/code_validation.dart +++ b/lib/src/screens/code_validation.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_otp_text_field/flutter_otp_text_field.dart'; +import 'package:get/get.dart'; +import 'package:prosappco/src/controllers/otp_controller.dart'; class CodeValidationScreen extends StatefulWidget { const CodeValidationScreen({super.key}); @@ -8,8 +11,11 @@ class CodeValidationScreen extends StatefulWidget { } class _CodeValidationScreenState extends State { + final controller = Get.put(OTPController()); + @override Widget build(BuildContext context) { + var otp; return SafeArea( child: Scaffold( resizeToAvoidBottomInset: false, @@ -76,7 +82,7 @@ class _CodeValidationScreenState extends State { child: TextField( decoration: InputDecoration( border: InputBorder.none, - hintText: '3102589636', + hintText: '+57', suffixIcon: Icon(Icons.edit), ), ), @@ -102,37 +108,50 @@ class _CodeValidationScreenState extends State { ), Padding( padding: EdgeInsets.only(bottom: 20), - child: TextField( - maxLength: 4, + child: OtpTextField( + numberOfFields: 6, + fillColor: Colors.black.withOpacity(0.1), + filled: true, keyboardType: TextInputType.number, - decoration: InputDecoration( - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Color(0xFFECECEC)), - borderRadius: BorderRadius.all( - Radius.circular(50), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Color(0xFFECECEC)), - borderRadius: BorderRadius.all( - Radius.circular(50), - ), - ), - hintText: '_ _ _ _', - fillColor: Color.fromARGB(255, 239, 239, 239), - filled: true, - ), - textAlign: TextAlign.center, - style: TextStyle( - letterSpacing: 12.0, - ), + onSubmit: (code) { + otp = code; + OTPController.instance.verifyOTP(otp); + }, ), + // child: TextField( + // onSubmitted: + // maxLength: 6, + // keyboardType: TextInputType.number, + // decoration: InputDecoration( + // enabledBorder: OutlineInputBorder( + // borderSide: BorderSide(color: Color(0xFFECECEC)), + // borderRadius: BorderRadius.all( + // Radius.circular(50), + // ), + // ), + // focusedBorder: OutlineInputBorder( + // borderSide: BorderSide(color: Color(0xFFECECEC)), + // borderRadius: BorderRadius.all( + // Radius.circular(50), + // ), + // ), + // hintText: '_ _ _ _ _ _', + // fillColor: Color.fromARGB(255, 239, 239, 239), + // filled: true, + // ), + // textAlign: TextAlign.center, + // style: TextStyle( + // letterSpacing: 10.0, + // ), + // ), ), Padding( padding: EdgeInsets.only(bottom: 40), child: Center( child: ElevatedButton( - onPressed: () {}, + onPressed: () { + OTPController.instance.verifyOTP(otp); + }, child: Text( 'Validar código', style: TextStyle( diff --git a/lib/src/screens/login.dart b/lib/src/screens/login.dart index fba6ffe..de6e6d5 100644 --- a/lib/src/screens/login.dart +++ b/lib/src/screens/login.dart @@ -1,12 +1,10 @@ -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:prosappco/src/provider/google_sign.dart'; +import 'package:get/get.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; +import 'package:prosappco/src/controllers/phone_auth_controller.dart'; import 'package:prosappco/src/screens/code_validation.dart'; import 'package:prosappco/src/screens/login_email.dart'; import 'package:prosappco/src/screens/register.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter/gestures.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -16,6 +14,9 @@ class LoginScreen extends StatefulWidget { } class _LoginScreenState extends State { + final controller = Get.put(PhoneAuthController()); + final _formKey = GlobalKey(); + @override Widget build(BuildContext context) { return SafeArea( @@ -67,24 +68,28 @@ class _LoginScreenState extends State { style: TextStyle( fontSize: 18.0, color: Color(0xFF65676B))), )), - const Padding( - padding: EdgeInsets.only(bottom: 10), - child: TextField( - decoration: InputDecoration( - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(color: Color(0xFFECECEC)), - borderRadius: BorderRadius.all( - Radius.circular(50), - )), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color: Color(0xFFECECEC)), - borderRadius: BorderRadius.all( - Radius.circular(50), - )), - hintText: '3163225944', - fillColor: Color.fromARGB(255, 239, 239, 239), - filled: true, - prefixIcon: Icon(Icons.phone_android_outlined)), + Form( + key: _formKey, + child: Padding( + padding: EdgeInsets.only(bottom: 10), + child: TextFormField( + controller: controller.phoneNo, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0xFFECECEC)), + borderRadius: BorderRadius.all( + Radius.circular(50), + )), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0xFFECECEC)), + borderRadius: BorderRadius.all( + Radius.circular(50), + )), + hintText: '+57', + fillColor: Color.fromARGB(255, 239, 239, 239), + filled: true, + prefixIcon: Icon(Icons.phone_android_outlined)), + ), ), ), const Padding( @@ -98,11 +103,12 @@ class _LoginScreenState extends State { child: Center( child: ElevatedButton( onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => CodeValidationScreen()), - ); + if (_formKey.currentState!.validate()) { + PhoneAuthController.instance.phoneAuthentication( + controller.phoneNo.text.trim(), + ); + Get.to(() => const CodeValidationScreen()); + } }, child: Text( 'Enviar código', diff --git a/lib/src/screens/login_email.dart b/lib/src/screens/login_email.dart index ae05567..0f4a863 100644 --- a/lib/src/screens/login_email.dart +++ b/lib/src/screens/login_email.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:prosappco/main.dart'; -import 'package:prosappco/src/provider/google_sign.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/screens/login.dart'; import 'package:prosappco/src/screens/welcome.dart'; import 'package:provider/provider.dart'; @@ -83,22 +83,8 @@ class _LoginEmailScreenState extends State { padding: EdgeInsets.only(bottom: 20), child: ElevatedButton( onPressed: () async { - try { - final UserCredential userCredential = - await signInWithGoogle(); - // Si la autenticación es exitosa, realiza una acción - // Por ejemplo, navegar a otra pantalla: - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => WelcomeScreen())); - } catch (e) { - // Si ocurre un error durante la autenticación, muestra un mensaje al usuario - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text( - 'Error al iniciar sesion intentalo de nuevo'), - )); - } + await AuthenticationRepository.instance + .signInWithGoogle(); }, style: ElevatedButton.styleFrom( primary: Color(0xFF2BA4EC), diff --git a/lib/src/screens/register.dart b/lib/src/screens/register.dart index 9a2acab..e7205f7 100644 --- a/lib/src/screens/register.dart +++ b/lib/src/screens/register.dart @@ -3,8 +3,8 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:prosappco/main.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; import 'package:prosappco/src/controllers/register_controller.dart'; -import 'package:prosappco/src/provider/google_sign.dart'; import 'package:prosappco/src/screens/login.dart'; import 'package:prosappco/src/screens/welcome.dart'; import 'package:provider/provider.dart'; @@ -84,22 +84,8 @@ class _RegisterScreenState extends State { padding: EdgeInsets.only(bottom: 20), child: ElevatedButton( onPressed: () async { - try { - final UserCredential userCredential = - await signInWithGoogle(); - // Si la autenticación es exitosa, realiza una acción - // Por ejemplo, navegar a otra pantalla: - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => WelcomeScreen())); - } catch (e) { - // Si ocurre un error durante la autenticación, muestra un mensaje al usuario - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text( - 'Error al iniciar sesion intentalo de nuevo'), - )); - } + await AuthenticationRepository.instance + .signInWithGoogle(); }, style: ElevatedButton.styleFrom( primary: Color(0xFF2BA4EC), diff --git a/lib/src/screens/welcome.dart b/lib/src/screens/welcome.dart index 17d9bfd..e2b8dcf 100644 --- a/lib/src/screens/welcome.dart +++ b/lib/src/screens/welcome.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:prosappco/src/authentication/authentication_repository.dart'; class WelcomeScreen extends StatefulWidget { const WelcomeScreen({super.key}); @@ -34,6 +35,34 @@ class _WelcomeScreenState extends State { height: 100, ), ), + Container( + child: Padding( + padding: const EdgeInsets.all(10), + child: Align( + alignment: Alignment.topRight, + child: ElevatedButton( + onPressed: () { + AuthenticationRepository.instance.logout(); + }, + child: Text( + 'Cerrar Sesión', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 15, + ), + ), + style: ElevatedButton.styleFrom( + primary: Color(0xFF2BA4EC), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + elevation: 0, + minimumSize: Size(150, 40), + ), + )), + ), + ), Container( padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 20), margin: const EdgeInsets.only(top: 170), diff --git a/pubspec.lock b/pubspec.lock index c4c535f..c7a0f7d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -126,6 +126,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + flutter_otp_text_field: + dependency: "direct main" + description: + name: flutter_otp_text_field + sha256: c9164ba391071fb9783698256ddbb9efc960cfed056d843db164711c65b1b114 + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter_test: dependency: "direct dev" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index e00f7e4..6187bef 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: provider: ^6.0.5 get: ^4.6.5 font_awesome_flutter: ^10.4.0 + flutter_otp_text_field: ^1.1.1 dev_dependencies: flutter_test: