diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 505f352..ab7716e 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,12 +1,15 @@ plugins { id("com.android.application") + // START: FlutterFire Configuration + id("com.google.gms.google-services") + // END: FlutterFire Configuration id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") } android { - namespace = "com.example.quentinha_app" + namespace = "com.quentinha.app" compileSdk = flutter.compileSdkVersion ndkVersion = "27.0.12077973" @@ -21,7 +24,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.quentinha_app" + applicationId = "com.quentinha.app" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..b34ecad --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,54 @@ +{ + "project_info": { + "project_number": "608998763205", + "project_id": "quentinha-app-c58a8", + "storage_bucket": "quentinha-app-c58a8.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:608998763205:android:a3826db7a993c65c04deac", + "android_client_info": { + "package_name": "com.quentinha.app" + } + }, + "oauth_client": [ + { + "client_id": "608998763205-ijepr4ls5hd5dk1a1d6qclqm38qj9frv.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.quentinha.app", + "certificate_hash": "aef0d5114d0ef947fc48eb0af7b07757955be9ce" + } + }, + { + "client_id": "608998763205-m6qa0cndknvofnvmebtv6tgll6l911ud.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBxw9c8DJALnvYGaPJ8nbmJNqPGDja9aLo" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "608998763205-m6qa0cndknvofnvmebtv6tgll6l911ud.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "608998763205-bolrakag8smuqli9vbb40ke0ki794kjr.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.example.quentinhaApp" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index ab39a10..bd7522f 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -19,6 +19,9 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.7.3" apply false + // START: FlutterFire Configuration + id("com.google.gms.google-services") version("4.3.15") apply false + // END: FlutterFire Configuration id("org.jetbrains.kotlin.android") version "2.1.0" apply false } diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..a48ea3e --- /dev/null +++ b/firebase.json @@ -0,0 +1,25 @@ +{ + "flutter": { + "platforms": { + "android": { + "default": { + "projectId": "quentinha-app-c58a8", + "appId": "1:608998763205:android:a3826db7a993c65c04deac", + "fileOutput": "android/app/google-services.json" + } + }, + "dart": { + "lib/firebase_options.dart": { + "projectId": "quentinha-app-c58a8", + "configurations": { + "android": "1:608998763205:android:a3826db7a993c65c04deac", + "ios": "1:608998763205:ios:238c1a0e7d449dd704deac", + "macos": "1:608998763205:ios:238c1a0e7d449dd704deac", + "web": "1:608998763205:web:3ae0b00196a1b9ae04deac", + "windows": "1:608998763205:web:5d6706b68bb7c79f04deac" + } + } + } + } + } +} \ No newline at end of file diff --git a/lib/auth/service/auth_method.dart b/lib/auth/service/auth_method.dart new file mode 100644 index 0000000..2f8fcfe --- /dev/null +++ b/lib/auth/service/auth_method.dart @@ -0,0 +1,83 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:quentinha_app/core/log/logger.dart'; + +class GoogleSignInService { + static final FirebaseAuth _auth = FirebaseAuth.instance; + static final GoogleSignIn _googleSignIn = GoogleSignIn.instance; + + static bool isInitialize = false; + + static Future initSignIn() async { + if (!isInitialize) { + await _googleSignIn.initialize( + serverClientId: + '608998763205-m6qa0cndknvofnvmebtv6tgll6l911ud.apps.googleusercontent.com', + ); + } + } + + static Future signInWithGoogle() async { + try { + initSignIn(); + final GoogleSignInAccount googleUser = await _googleSignIn.authenticate(); + final idToken = googleUser.authentication.idToken; + final authorizationClient = googleUser.authorizationClient; + GoogleSignInClientAuthorization? authorization = await authorizationClient + .authorizationForScopes(['email', 'profile']); + + final accessToken = authorization?.accessToken; + if (accessToken == null) { + final authorization2 = await authorizationClient.authorizationForScopes( + ['email', 'profile'], + ); + + if (authorization2?.accessToken == null) { + throw FirebaseAuthException(code: 'error', message: 'error'); + } + authorization = authorization2; + } + final credential = GoogleAuthProvider.credential( + accessToken: accessToken, + idToken: idToken, + ); + + final UserCredential userCredential = await FirebaseAuth.instance + .signInWithCredential(credential); + final User? user = userCredential.user; + if (user != null) { + final userDoc = FirebaseFirestore.instance + .collection('users') + .doc(user.uid); + final docSnapshot = await userDoc.get(); + if (!docSnapshot.exists) { + await userDoc.set({ + 'uid': user.uid, + 'name': user.displayName ?? '', + 'email': user.email ?? '', + 'photoURL': user.photoURL ?? '', + 'provider': 'google', + 'createdAt': FieldValue.serverTimestamp(), + }); + } + } + return userCredential; + } catch (e) { + AppLogger.e('Error during Google Sign-In: $e'); + rethrow; + } + } + + static Future signOut() async { + try { + await _googleSignIn.signOut(); + await _auth.signOut(); + } catch (e) { + AppLogger.e('Error during Google Sign-Out: $e'); + rethrow; + } + } + + static User? get currentUser => _auth.currentUser; +} diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 0000000..cf26397 --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,90 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: type=lint +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + return macos; + case TargetPlatform.windows: + return windows; + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions web = FirebaseOptions( + apiKey: 'AIzaSyBOdGqAn4lLvlEq59eOoINokEPHbS42RQQ', + appId: '1:608998763205:web:3ae0b00196a1b9ae04deac', + messagingSenderId: '608998763205', + projectId: 'quentinha-app-c58a8', + authDomain: 'quentinha-app-c58a8.firebaseapp.com', + storageBucket: 'quentinha-app-c58a8.firebasestorage.app', + ); + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyBxw9c8DJALnvYGaPJ8nbmJNqPGDja9aLo', + appId: '1:608998763205:android:a3826db7a993c65c04deac', + messagingSenderId: '608998763205', + projectId: 'quentinha-app-c58a8', + storageBucket: 'quentinha-app-c58a8.firebasestorage.app', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyCcC4p61OnLs0RZgdhFbUOxWcHidlW-bng', + appId: '1:608998763205:ios:238c1a0e7d449dd704deac', + messagingSenderId: '608998763205', + projectId: 'quentinha-app-c58a8', + storageBucket: 'quentinha-app-c58a8.firebasestorage.app', + iosClientId: + '608998763205-bolrakag8smuqli9vbb40ke0ki794kjr.apps.googleusercontent.com', + iosBundleId: 'com.example.quentinhaApp', + ); + + static const FirebaseOptions macos = FirebaseOptions( + apiKey: 'AIzaSyCcC4p61OnLs0RZgdhFbUOxWcHidlW-bng', + appId: '1:608998763205:ios:238c1a0e7d449dd704deac', + messagingSenderId: '608998763205', + projectId: 'quentinha-app-c58a8', + storageBucket: 'quentinha-app-c58a8.firebasestorage.app', + iosClientId: + '608998763205-bolrakag8smuqli9vbb40ke0ki794kjr.apps.googleusercontent.com', + iosBundleId: 'com.example.quentinhaApp', + ); + + static const FirebaseOptions windows = FirebaseOptions( + apiKey: 'AIzaSyBOdGqAn4lLvlEq59eOoINokEPHbS42RQQ', + appId: '1:608998763205:web:5d6706b68bb7c79f04deac', + messagingSenderId: '608998763205', + projectId: 'quentinha-app-c58a8', + authDomain: 'quentinha-app-c58a8.firebaseapp.com', + storageBucket: 'quentinha-app-c58a8.firebasestorage.app', + ); +} diff --git a/lib/main.dart b/lib/main.dart index f4b82e5..38ae076 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,11 @@ +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:quentinha_app/core/consts/colors_const.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'core/routes/routes.dart'; +import 'firebase_options.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -14,7 +16,7 @@ void main() async { final prefs = await SharedPreferences.getInstance(); final bool? seenOnboarding = prefs.getBool('seenOnboarding'); - + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); runApp(MyApp(seenOnboarding: seenOnboarding ?? false)); } @@ -27,14 +29,12 @@ class MyApp extends StatelessWidget { return MaterialApp.router( theme: ThemeData( primaryColor: AppColors.primary, - textSelectionTheme: TextSelectionThemeData( + textSelectionTheme: TextSelectionThemeData( cursorColor: AppColors.primary, // cursor selectionColor: Colors.orangeAccent, // texto selecionado selectionHandleColor: Colors.orange, // "bolinha" do seletor ), - textTheme: GoogleFonts.robotoTextTheme( - Theme.of(context).textTheme, - ), + textTheme: GoogleFonts.robotoTextTheme(Theme.of(context).textTheme), ), title: 'Quentinhas App', debugShowCheckedModeBanner: false, diff --git a/lib/presentation/view/login_page.dart b/lib/presentation/view/login_page.dart index efd02ef..eae936b 100644 --- a/lib/presentation/view/login_page.dart +++ b/lib/presentation/view/login_page.dart @@ -1,3 +1,4 @@ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; @@ -18,16 +19,21 @@ class LoginPage extends StatefulWidget { class _LoginPageState extends State { final _formKey = GlobalKey(); + final TextEditingController _emailController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); bool rememberAccount = false; void _signOn() async { - if (_formKey.currentState!.validate()) { - // Fecha teclado - FocusManager.instance.primaryFocus?.unfocus(); - await Future.delayed(const Duration(milliseconds: 200)); + if (_formKey.currentState!.validate()) { + FocusManager.instance.primaryFocus?.unfocus(); - // Mostra loading + snackbar + try { + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: _emailController.text.trim(), + password: _passwordController.text.trim(), + ); + + // Se deu certo: await CustomSnackBar.showWithLoading( context, message: "Login realizado com sucesso!", @@ -36,18 +42,28 @@ class _LoginPageState extends State { delay: const Duration(seconds: 2), ); - // Navega para a página de login - if (mounted) { - final prefs = await SharedPreferences.getInstance(); - await prefs.setBool('seenOnboarding', true); + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool('seenOnboarding', true); - // Usando GoRouter para navegação - // Certifique-se de ter configurado a rota '/home' no seu GoRouter - // e de importar 'package:go_router/go_router.dart' - context.go(AppNameRoutes.home); + if (mounted) context.go(AppNameRoutes.home); + } on FirebaseAuthException catch (e) { + String message = "Erro ao fazer login."; + if (e.code == 'user-not-found') { + message = "Usuário não encontrado."; + } else if (e.code == 'wrong-password') { + message = "Senha incorreta."; } + CustomSnackBar.show( + context, + message: message, + backgroundColor: Colors.red, + icon: Icons.error, + ); } } +} + + @override Widget build(BuildContext context) { @@ -128,6 +144,7 @@ class _LoginPageState extends State { const Text("EMAIL"), 8.h, TextFormField( + controller: _emailController, decoration: InputDecoration( hintText: "exemplo@gmail.com", filled: true, diff --git a/pubspec.yaml b/pubspec.yaml index 2d45c0e..45e25a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,6 +42,10 @@ dependencies: google_fonts: ^6.3.1 pinput: ^5.0.2 badges: ^3.1.2 + firebase_core: ^4.2.0 + firebase_auth: ^6.1.1 + google_sign_in: ^7.2.0 + cloud_firestore: ^6.0.3 dev_dependencies: flutter_test: