Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
analyzer:
errors:
use_build_context_synchronously: ignore
include: package:flutter_lints/flutter.yaml

linter:
Expand Down
9 changes: 4 additions & 5 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {

android {
namespace = "com.example.firebase_multi_auth_guide"
compileSdk = flutter.compileSdkVersion
compileSdkVersion 34
ndkVersion = flutter.ndkVersion

compileOptions {
Expand All @@ -27,16 +27,15 @@ android {
applicationId = "com.example.firebase_multi_auth_guide"
// 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
targetSdk = flutter.targetSdkVersion
minSdkVersion 23
targetSdkVersion 34
versionCode = flutter.versionCode
versionName = flutter.versionName
}

buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.

signingConfig = signingConfigs.debug
}
}
Expand Down
37 changes: 35 additions & 2 deletions android/app/google-services.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,48 @@
"package_name": "com.example.firebase_multi_auth_guide"
}
},
"oauth_client": [],
"oauth_client": [
{
"client_id": "1096731177237-btghj6gdb60cam4mc086ckhq81c7iaqe.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.example.firebase_multi_auth_guide",
"certificate_hash": "20121cceaa7c57b61696787d881a614b6b90fad7"
}
},
{
"client_id": "1096731177237-pc42l34v7vavjcsqrvnbgq1amvdd85al.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.example.firebase_multi_auth_guide",
"certificate_hash": "e0382aa71e5b75a930791eac7ff65e3ae6011692"
}
},
{
"client_id": "1096731177237-keco1o97ntmta8eaub2lvp380hghth7l.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBEMJlekKjMYTzndbsUPwqZWq99NAnDEW0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
"other_platform_oauth_client": [
{
"client_id": "1096731177237-keco1o97ntmta8eaub2lvp380hghth7l.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "1096731177237-i3gm5hk9gjvi5bhkma3jfnpmkii6o7fn.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.example.firebaseMultiAuthGuide"
}
}
]
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ class FirebaseMultiAuthGuide extends StatelessWidget {
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Firebase Multi Auth Guide',
home:RegisterPage(),

home: RegisterPage(),
);
}
}
145 changes: 145 additions & 0 deletions lib/helpers/auth_with_google.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import 'dart:developer';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:flutter/material.dart';

class AuthResult {
final bool success;
final UserCredential? userCredential;
final String message;

AuthResult({
required this.success,
this.userCredential,
required this.message,
});
}

class AuthWithGoogleHelper {
static Future<AuthResult> signInWithGoogle() async {
try {
// Trigger the authentication flow
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();

// User canceled the sign-in flow
if (googleUser == null) {
return AuthResult(
success: false,
message: 'Sign in cancelled by user',
);
}

try {
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;

// Log user information for debugging
log('User Email: ${googleUser.email}');
log('User Name: ${googleUser.displayName}');
log('User Photo URL: ${googleUser.photoUrl ?? "No photo"}');

// Create a new credential
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);

// Sign in to Firebase with the Google credential
final userCredential =
await FirebaseAuth.instance.signInWithCredential(credential);

return AuthResult(
success: true,
userCredential: userCredential,
message: 'Successfully signed in with Google',
);
} catch (e) {
log('Error during Google authentication: $e');
return AuthResult(
success: false,
message: 'Failed to authenticate with Google. Please try again.',
);
}
} on FirebaseAuthException catch (e) {
log('FirebaseAuthException: $e');
String message;
switch (e.code) {
case 'account-exists-with-different-credential':
message =
'An account already exists with the same email but different sign-in credentials.';
break;
case 'invalid-credential':
message = 'The authentication credential is invalid.';
break;
case 'operation-not-allowed':
message = 'Google sign-in is not enabled for this project.';
break;
case 'user-disabled':
message = 'This user account has been disabled.';
break;
case 'user-not-found':
message = 'No user found for that email.';
break;
default:
message = 'An unknown error occurred. Please try again.';
}
return AuthResult(success: false, message: message);
} catch (e) {
log('Unexpected error during Google sign in: $e');
return AuthResult(
success: false,
message: 'An unexpected error occurred. Please try again.',
);
}
}
}

// Extension to show SnackBars more easily
extension ShowSnackBar on BuildContext {
void showSuccessSnackBar(String message) {
ScaffoldMessenger.of(this).showSnackBar(
SnackBar(
content: Row(
children: [
const Icon(Icons.check_circle, color: Colors.white),
const SizedBox(width: 8),
Expanded(
child: Text(
message,
style: const TextStyle(color: Colors.white),
),
),
],
),
backgroundColor: Colors.green.shade600,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
duration: const Duration(seconds: 4),
),
);
}

void showErrorSnackBar(String message) {
ScaffoldMessenger.of(this).showSnackBar(
SnackBar(
content: Row(
children: [
const Icon(Icons.error, color: Colors.white),
const SizedBox(width: 8),
Expanded(
child: Text(
message,
style: const TextStyle(color: Colors.white),
),
),
],
),
backgroundColor: Colors.red.shade600,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
duration: const Duration(seconds: 4),
),
);
}
}
86 changes: 12 additions & 74 deletions lib/pages/login_page_.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'package:firebase_multi_auth_guide/pages/register_page.dart';
import 'package:firebase_multi_auth_guide/widgets/full_width_button.dart';
import 'package:firebase_multi_auth_guide/widgets/google_sign_in_button.dart';
import 'package:firebase_multi_auth_guide/widgets/login_button.dart';
import 'package:flutter/material.dart';

class LoginPage extends StatelessWidget {
Expand Down Expand Up @@ -50,37 +53,32 @@ class LoginPage extends StatelessWidget {
crossAxisSpacing: 16,
childAspectRatio: 2.5,
children: [
_buildLoginButton(
text: 'Google',
color: Colors.red.shade400,
icon: Icons.g_mobiledata,
onPressed: () {},
),
_buildLoginButton(
const GoogleSignInButton(),
LoginButton(
text: 'Facebook',
color: Colors.blue.shade600,
icon: Icons.facebook,
onPressed: () {},
),
_buildLoginButton(
LoginButton(
text: 'Twitter',
color: Colors.lightBlue.shade400,
icon: Icons.alternate_email,
onPressed: () {},
),
_buildLoginButton(
LoginButton(
text: 'GitHub',
color: Colors.black87,
icon: Icons.code,
onPressed: () {},
),
_buildLoginButton(
LoginButton(
text: 'Microsoft',
color: Colors.blue.shade800,
icon: Icons.window,
onPressed: () {},
),
_buildLoginButton(
LoginButton(
text: 'Apple',
color: Colors.black,
icon: Icons.apple,
Expand All @@ -97,21 +95,21 @@ class LoginPage extends StatelessWidget {
),
),
const SizedBox(height: 24),
_buildFullWidthButton(
FullWidthButton(
text: 'Email and Password',
color: Colors.deepPurple.shade400,
icon: Icons.email,
onPressed: () {},
),
const SizedBox(height: 16),
_buildFullWidthButton(
FullWidthButton(
text: 'Phone Number',
color: Colors.green.shade600,
icon: Icons.phone,
onPressed: () {},
),
const SizedBox(height: 16),
_buildFullWidthButton(
FullWidthButton(
text: 'Continue as Guest',
color: Colors.grey.shade700,
icon: Icons.person_outline,
Expand Down Expand Up @@ -151,64 +149,4 @@ class LoginPage extends StatelessWidget {
),
);
}

Widget _buildLoginButton({
required String text,
required Color color,
required IconData icon,
required VoidCallback onPressed,
}) {
return ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: color,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 20),
const SizedBox(width: 8),
Text(
text,
style: const TextStyle(fontSize: 14),
),
],
),
);
}

Widget _buildFullWidthButton({
required String text,
required Color color,
required IconData icon,
required VoidCallback onPressed,
}) {
return ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: color,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 24),
const SizedBox(width: 12),
Text(
text,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
],
),
);
}
}
Loading