From e281aa99f30310ad959872535d740bb7becd327f Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:42:32 +0300 Subject: [PATCH 01/21] build: add deps --- pubspec.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pubspec.yaml b/pubspec.yaml index c7df9c7..df9d264 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,8 @@ dependencies: supabase_flutter: ^2.0.1 email_validator: ^2.0.1 font_awesome_flutter: ^10.6.0 + google_sign_in: ^6.2.1 + sign_in_with_apple: ^5.0.0 dev_dependencies: flutter_test: From ba545fbc905bbb69f87638832f998474233c7ccb Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Wed, 3 Jan 2024 23:48:48 +0300 Subject: [PATCH 02/21] unrelated - clean up --- lib/src/components/supa_socials_auth.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index 79b635e..bbcbacc 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -200,7 +200,6 @@ class _SupaSocialsAuthState extends State { ); break; default: - // Handle other cases or provide a default behavior. break; } From a676252c0685bcb0d1ca822b76d18e04dee7aeec Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Thu, 4 Jan 2024 11:26:08 +0300 Subject: [PATCH 03/21] =?UTF-8?q?feat:=20add=20native=20google=20sign=20in?= =?UTF-8?q?=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/components/supa_native_auth.dart | 65 ++++++++++++++++++++++++ lib/supabase_auth_ui.dart | 1 + 2 files changed, 66 insertions(+) create mode 100644 lib/src/components/supa_native_auth.dart diff --git a/lib/src/components/supa_native_auth.dart b/lib/src/components/supa_native_auth.dart new file mode 100644 index 0000000..42866d9 --- /dev/null +++ b/lib/src/components/supa_native_auth.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:supabase_auth_ui/src/utils/constants.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; + +enum NativeProviders { apple, google } + +class SupaNativeAuth extends StatefulWidget { + final String webClientId, iosClientId; + const SupaNativeAuth( + {super.key, required this.webClientId, required this.iosClientId}); + + @override + State createState() => _SupaNativeAuthState(); +} + +class _SupaNativeAuthState extends State { + Future _googleSignIn(webClientId, iosClientId) async { + /// TODO: update the Web client ID with your own. + /// + /// Web Client ID that you registered with Google Cloud. + // const webClientId = 'my-web.apps.googleusercontent.com'; + + /// TODO: update the iOS client ID with your own. + /// + /// iOS Client ID that you registered with Google Cloud. + // const iosClientId = 'my-ios.apps.googleusercontent.com'; + + // Google sign in on Android will work without providing the Android + // Client ID registered on Google Cloud. + + final GoogleSignIn googleSignIn = GoogleSignIn( + clientId: iosClientId, + serverClientId: webClientId, + ); + final googleUser = await googleSignIn.signIn(); + final googleAuth = await googleUser!.authentication; + final accessToken = googleAuth.accessToken; + final idToken = googleAuth.idToken; + + if (accessToken == null) { + throw 'No Access Token found.'; + } + if (idToken == null) { + throw 'No ID Token found.'; + } + + return supabase.auth.signInWithIdToken( + provider: OAuthProvider.google, + idToken: idToken, + accessToken: accessToken, + ); + } + + @override + Widget build(BuildContext context) { + final webClientId = widget.webClientId; + final iosClientId = widget.iosClientId; + return ElevatedButton( + onPressed: () async { + await _googleSignIn(webClientId, iosClientId); + }, + child: const Text('Sign in with Google')); + } +} diff --git a/lib/supabase_auth_ui.dart b/lib/supabase_auth_ui.dart index 3799793..60234c3 100644 --- a/lib/supabase_auth_ui.dart +++ b/lib/supabase_auth_ui.dart @@ -6,5 +6,6 @@ export 'src/components/supa_reset_password.dart'; export 'src/components/supa_socials_auth.dart'; export 'src/components/supa_phone_auth.dart'; export 'src/components/supa_verify_phone.dart'; +export 'src/components/supa_native_auth.dart'; export 'src/utils/supa_auth_action.dart'; export 'package:supabase_flutter/supabase_flutter.dart'; From 15811388bada5017cb3f8a7252a305a7ffceed8d Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Fri, 5 Jan 2024 23:08:42 +0300 Subject: [PATCH 04/21] build: update sdk, add crypto dep --- pubspec.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index df9d264..b87c1fd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,11 +2,11 @@ name: supabase_auth_ui description: UI library to implement auth forms using Supabase and Flutter version: 0.4.0+1 homepage: https://supabase.com -repository: 'https://github.com/supabase-community/flutter-auth-ui' +repository: "https://github.com/supabase-community/flutter-auth-ui" environment: - sdk: '>=3.0.0 <4.0.0' - flutter: '>=3.0.0' + sdk: ">=3.0.0 <4.0.0" + flutter: ">=3.0.0" dependencies: flutter: @@ -16,6 +16,7 @@ dependencies: font_awesome_flutter: ^10.6.0 google_sign_in: ^6.2.1 sign_in_with_apple: ^5.0.0 + crypto: ^3.0.3 dev_dependencies: flutter_test: From 874ca0cd969c25f5aaf6b7ea9ca840d339301e03 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Fri, 5 Jan 2024 23:09:26 +0300 Subject: [PATCH 05/21] chore: clean up --- lib/src/components/supa_native_auth.dart | 72 ++++++++++++++++++------ 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/lib/src/components/supa_native_auth.dart b/lib/src/components/supa_native_auth.dart index 42866d9..1eda05e 100644 --- a/lib/src/components/supa_native_auth.dart +++ b/lib/src/components/supa_native_auth.dart @@ -1,38 +1,44 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_sign_in/google_sign_in.dart'; +import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import 'package:supabase_auth_ui/src/utils/constants.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; -enum NativeProviders { apple, google } - class SupaNativeAuth extends StatefulWidget { + /// Web Client ID and iOS Client ID that you registered with Google Cloud. final String webClientId, iosClientId; - const SupaNativeAuth( - {super.key, required this.webClientId, required this.iosClientId}); + + /// Callback for the user to complete a sign in. + final void Function(AuthResponse response) onSignInComplete; + + /// Callback for the user to complete a signUp. + final void Function(AuthResponse response) onSignUpComplete; + + const SupaNativeAuth({ + super.key, + required this.webClientId, + required this.iosClientId, + required this.onSignInComplete, + required this.onSignUpComplete, + }); @override State createState() => _SupaNativeAuthState(); } class _SupaNativeAuthState extends State { + /// Performs Google sign in on Android and iOS Future _googleSignIn(webClientId, iosClientId) async { - /// TODO: update the Web client ID with your own. - /// - /// Web Client ID that you registered with Google Cloud. - // const webClientId = 'my-web.apps.googleusercontent.com'; - - /// TODO: update the iOS client ID with your own. - /// - /// iOS Client ID that you registered with Google Cloud. - // const iosClientId = 'my-ios.apps.googleusercontent.com'; - - // Google sign in on Android will work without providing the Android - // Client ID registered on Google Cloud. - final GoogleSignIn googleSignIn = GoogleSignIn( clientId: iosClientId, serverClientId: webClientId, ); + final googleUser = await googleSignIn.signIn(); final googleAuth = await googleUser!.authentication; final accessToken = googleAuth.accessToken; @@ -52,13 +58,43 @@ class _SupaNativeAuthState extends State { ); } + /// Performs Apple sign in on iOS or macOS + Future _appleSignIn() async { + final rawNonce = supabase.auth.generateRawNonce(); + final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString(); + + final credential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + nonce: hashedNonce, + ); + + final idToken = credential.identityToken; + if (idToken == null) { + throw const AuthException( + 'Could not find ID Token from generated credential.'); + } + + return supabase.auth.signInWithIdToken( + provider: OAuthProvider.apple, + idToken: idToken, + nonce: rawNonce, + ); + } + @override Widget build(BuildContext context) { final webClientId = widget.webClientId; final iosClientId = widget.iosClientId; return ElevatedButton( onPressed: () async { - await _googleSignIn(webClientId, iosClientId); + Platform.isAndroid + ? await _googleSignIn(webClientId, iosClientId) + : Platform.isIOS + ? await _appleSignIn() + : null; }, child: const Text('Sign in with Google')); } From d66eb3b363d02893b4ca4fc95d34755f878e2820 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:51:47 +0300 Subject: [PATCH 06/21] refactor: have it support both google and apple --- lib/src/components/supa_native_auth.dart | 128 ++++++++++++++++++----- 1 file changed, 103 insertions(+), 25 deletions(-) diff --git a/lib/src/components/supa_native_auth.dart b/lib/src/components/supa_native_auth.dart index 1eda05e..37f6887 100644 --- a/lib/src/components/supa_native_auth.dart +++ b/lib/src/components/supa_native_auth.dart @@ -1,30 +1,49 @@ -import 'dart:convert'; -import 'dart:io'; +import 'dart:async'; -import 'package:crypto/crypto.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'dart:convert'; +import 'package:crypto/crypto.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import 'package:supabase_auth_ui/src/utils/constants.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; -class SupaNativeAuth extends StatefulWidget { +class AuthType { + GoogleAuthType? google; + bool apple; + + AuthType({this.google, required this.apple}); +} + +class GoogleAuthType { /// Web Client ID and iOS Client ID that you registered with Google Cloud. - final String webClientId, iosClientId; + /// Needed for Sign in with Google + String webClientId; + String iosClientId; + + GoogleAuthType({required this.webClientId, required this.iosClientId}); +} + +class SupaNativeAuth extends StatefulWidget { + /// Defines native auth providers to show in the form + final AuthType authType; + + /// Method to be called when the auth action is success + final void Function(Session) onSuccess; - /// Callback for the user to complete a sign in. - final void Function(AuthResponse response) onSignInComplete; + /// Method to be called when the auth action threw an excepction + final void Function(Object error)? onError; - /// Callback for the user to complete a signUp. - final void Function(AuthResponse response) onSignUpComplete; + /// Whether to show a SnackBar after a successful sign in + final bool showSuccessSnackBar; const SupaNativeAuth({ super.key, - required this.webClientId, - required this.iosClientId, - required this.onSignInComplete, - required this.onSignUpComplete, + required this.authType, + required this.onSuccess, + this.onError, + this.showSuccessSnackBar = true, }); @override @@ -84,18 +103,77 @@ class _SupaNativeAuthState extends State { ); } + Widget _nativeAuthBtn( + IconData icon, String label, Future Function() signInMethod) { + return ElevatedButton.icon( + onPressed: () async { + try { + await signInMethod(); + } on AuthException catch (error) { + if (widget.onError == null && context.mounted) { + context.showErrorSnackBar(error.message); + } else { + widget.onError?.call(error); + } + } catch (error) { + if (widget.onError == null && context.mounted) { + context.showErrorSnackBar('Unexpected error has occurred: $error'); + } else { + widget.onError?.call(error); + } + } + }, + icon: Icon(icon), + label: Text(label), + ); + } + + late final StreamSubscription _gotrueSubscription; + + @override + void initState() { + super.initState(); + _gotrueSubscription = + Supabase.instance.client.auth.onAuthStateChange.listen((data) { + final session = data.session; + if (session != null && mounted) { + widget.onSuccess.call(session); + if (widget.showSuccessSnackBar) { + context.showSnackBar('Successfully signed in!'); + } + } + }); + } + + @override + void dispose() { + super.dispose(); + _gotrueSubscription.cancel(); + } + @override Widget build(BuildContext context) { - final webClientId = widget.webClientId; - final iosClientId = widget.iosClientId; - return ElevatedButton( - onPressed: () async { - Platform.isAndroid - ? await _googleSignIn(webClientId, iosClientId) - : Platform.isIOS - ? await _appleSignIn() - : null; - }, - child: const Text('Sign in with Google')); + final provider = widget.authType; + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (provider.google != null) + _nativeAuthBtn( + FontAwesomeIcons.google, + 'Sign in with Google', + () => _googleSignIn( + provider.google!.webClientId, + provider.google!.iosClientId, + ), + ), + if (provider.apple) + _nativeAuthBtn( + FontAwesomeIcons.apple, + 'Sign in with Apple', + _appleSignIn, + ), + ], + ); } } From 05c5f5d475c7dc79d753e418aa3dfc59880af292 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Tue, 9 Jan 2024 00:31:59 +0300 Subject: [PATCH 07/21] minor fixes for social auth --- lib/src/components/supa_socials_auth.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index bbcbacc..68cdcc9 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -5,7 +5,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:supabase_auth_ui/src/utils/constants.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; -extension SocialProvidersa on OAuthProvider { +extension SocialProviders on OAuthProvider { IconData get _iconData => switch (this) { OAuthProvider.apple => FontAwesomeIcons.apple, OAuthProvider.azure => FontAwesomeIcons.microsoft, @@ -20,7 +20,7 @@ extension SocialProvidersa on OAuthProvider { OAuthProvider.slack => FontAwesomeIcons.slack, OAuthProvider.spotify => FontAwesomeIcons.spotify, OAuthProvider.twitch => FontAwesomeIcons.twitch, - OAuthProvider.twitter => FontAwesomeIcons.x, + OAuthProvider.twitter => FontAwesomeIcons.xTwitter, _ => Icons.close, }; From 4da15fa80a2d1bd60cc9583ba8196a87ff67f7e6 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Tue, 9 Jan 2024 01:02:23 +0300 Subject: [PATCH 08/21] refactor and style: make params named, add styles --- lib/src/components/supa_native_auth.dart | 78 ++++++++++++++++-------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/lib/src/components/supa_native_auth.dart b/lib/src/components/supa_native_auth.dart index 37f6887..6cd6af2 100644 --- a/lib/src/components/supa_native_auth.dart +++ b/lib/src/components/supa_native_auth.dart @@ -104,27 +104,42 @@ class _SupaNativeAuthState extends State { } Widget _nativeAuthBtn( - IconData icon, String label, Future Function() signInMethod) { - return ElevatedButton.icon( - onPressed: () async { - try { - await signInMethod(); - } on AuthException catch (error) { - if (widget.onError == null && context.mounted) { - context.showErrorSnackBar(error.message); - } else { - widget.onError?.call(error); + {required Widget icon, + required String label, + required Color bgColor, + required Color textColor, + required Future Function() signInMethod}) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), + child: ElevatedButton.icon( + onPressed: () async { + try { + await signInMethod(); + } on AuthException catch (error) { + if (widget.onError == null && context.mounted) { + context.showErrorSnackBar(error.message); + } else { + widget.onError?.call(error); + } + } catch (error) { + if (widget.onError == null && context.mounted) { + context + .showErrorSnackBar('Unexpected error has occurred: $error'); + } else { + widget.onError?.call(error); + } } - } catch (error) { - if (widget.onError == null && context.mounted) { - context.showErrorSnackBar('Unexpected error has occurred: $error'); - } else { - widget.onError?.call(error); - } - } - }, - icon: Icon(icon), - label: Text(label), + }, + icon: icon, + label: Text(label), + style: ElevatedButton.styleFrom( + backgroundColor: bgColor, + foregroundColor: textColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + ), + ), ); } @@ -160,18 +175,29 @@ class _SupaNativeAuthState extends State { children: [ if (provider.google != null) _nativeAuthBtn( - FontAwesomeIcons.google, - 'Sign in with Google', - () => _googleSignIn( + icon: Image.asset( + 'assets/logos/google_light.png', + package: 'supabase_auth_ui', + width: 36, + height: 36, + ), + label: 'Sign in with Google', + signInMethod: () => _googleSignIn( provider.google!.webClientId, provider.google!.iosClientId, ), + bgColor: const Color.fromRGBO(242, 242, 242, 1), + textColor: Colors.black, ), if (provider.apple) _nativeAuthBtn( - FontAwesomeIcons.apple, - 'Sign in with Apple', - _appleSignIn, + icon: const Icon( + FontAwesomeIcons.apple, + ), + label: 'Sign in with Apple', + signInMethod: _appleSignIn, + bgColor: Colors.black, + textColor: Colors.white, ), ], ); From f4f9d61422fece159c4ef6abca906597b1732bb4 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Tue, 9 Jan 2024 01:11:37 +0300 Subject: [PATCH 09/21] feat: add basic example to example/lib/sign in --- example/lib/sign_in.dart | 13 +++++++++++++ text | 7 +++++++ 2 files changed, 20 insertions(+) create mode 100644 text diff --git a/example/lib/sign_in.dart b/example/lib/sign_in.dart index 214ae1c..36805d3 100644 --- a/example/lib/sign_in.dart +++ b/example/lib/sign_in.dart @@ -55,6 +55,19 @@ class SignUp extends StatelessWidget { label: const Text('Sign in with Phone'), ), spacer, + SupaNativeAuth( + authType: AuthType( + google: GoogleAuthType( + webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com', + iosClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com', + ), + apple: true, + ), + onSuccess: (response) { + Navigator.of(context).pushReplacementNamed('/home'); + }, + ), + spacer, SupaSocialsAuth( colored: true, socialProviders: OAuthProvider.values, diff --git a/text b/text new file mode 100644 index 0000000..7677126 --- /dev/null +++ b/text @@ -0,0 +1,7 @@ + url: 'https://xlvhpbcxavkjwhvvumjr.supabase.co', + anonKey: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzOTIyNDEzNSwiZXhwIjoxOTU0ODAwMTM1fQ.HZ4d4SdD40txeDY71d010S914KgrKYJNAzkrRU0C07w', + webClientId: + '586179364408-p0cloviile92cndu00sshbm3qjc0vugt.apps.googleusercontent.com', + iosClientId: + '586179364408-9c4rhej5pdal0vggiteuqjcbsfuf8an8.apps.googleusercontent.com', \ No newline at end of file From 7cbe2ab81fe81fe8eba7537c17fecab41faaa6f2 Mon Sep 17 00:00:00 2001 From: Fatuma Abdullahi <67555014+FatumaA@users.noreply.github.com> Date: Wed, 10 Jan 2024 12:58:41 +0300 Subject: [PATCH 10/21] Delete text --- text | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 text diff --git a/text b/text deleted file mode 100644 index 7677126..0000000 --- a/text +++ /dev/null @@ -1,7 +0,0 @@ - url: 'https://xlvhpbcxavkjwhvvumjr.supabase.co', - anonKey: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzOTIyNDEzNSwiZXhwIjoxOTU0ODAwMTM1fQ.HZ4d4SdD40txeDY71d010S914KgrKYJNAzkrRU0C07w', - webClientId: - '586179364408-p0cloviile92cndu00sshbm3qjc0vugt.apps.googleusercontent.com', - iosClientId: - '586179364408-9c4rhej5pdal0vggiteuqjcbsfuf8an8.apps.googleusercontent.com', \ No newline at end of file From 4468897a1bd68c0d58c481c5168e4ab7dd187bf2 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:10:48 +0300 Subject: [PATCH 11/21] refactor: combine supanative auth & supasocials auth --- lib/src/components/supa_socials_auth.dart | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index 4f35ae8..4ebb320 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -58,8 +58,40 @@ enum SocialButtonVariant { iconAndText, } +// class NativeGoogleAuthConfig { +// GoogleNativeAuthConfig? google; +// bool enableNativeAppleAuth; + +// NativeGoogleAuthConfig({this.google, required this.enableNativeAppleAuth}); +// } + +class NativeGoogleAuthConfig { + /// Web Client ID and iOS Client ID that you registered with Google Cloud. + /// Needed for Sign in with Google + String webClientId; + String iosClientId; + + NativeGoogleAuthConfig( + {required this.webClientId, required this.iosClientId}); +} + +class GoogleNativeAuthConfig { + /// Web Client ID and iOS Client ID that you registered with Google Cloud. + /// Needed for Sign in with Google + String webClientId; + String iosClientId; + + GoogleNativeAuthConfig( + {required this.webClientId, required this.iosClientId}); +} + /// UI Component to create social login form class SupaSocialsAuth extends StatefulWidget { + /// Defines native auth providers to show in the form + final NativeGoogleAuthConfig? nativeGoogleAuthConfig; + + final bool? enableNativeAppleAuth; + /// List of social providers to show in the form final List socialProviders; @@ -87,6 +119,8 @@ class SupaSocialsAuth extends StatefulWidget { const SupaSocialsAuth({ Key? key, + this.nativeGoogleAuthConfig, + this.enableNativeAppleAuth, required this.socialProviders, this.colored = true, this.redirectUrl, From dcb53359bed5fccd7a91e70a19d1134bff0eb966 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:11:21 +0300 Subject: [PATCH 12/21] refactor: update example to the new api --- example/lib/sign_in.dart | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/example/lib/sign_in.dart b/example/lib/sign_in.dart index 36805d3..5836361 100644 --- a/example/lib/sign_in.dart +++ b/example/lib/sign_in.dart @@ -55,21 +55,13 @@ class SignUp extends StatelessWidget { label: const Text('Sign in with Phone'), ), spacer, - SupaNativeAuth( - authType: AuthType( - google: GoogleAuthType( - webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com', - iosClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com', - ), - apple: true, - ), - onSuccess: (response) { - Navigator.of(context).pushReplacementNamed('/home'); - }, - ), - spacer, SupaSocialsAuth( colored: true, + nativeGoogleAuthConfig: NativeGoogleAuthConfig( + webClientId: '', + iosClientId: '', + ), + enableNativeAppleAuth: false, socialProviders: OAuthProvider.values, onSuccess: (session) { Navigator.of(context).pushReplacementNamed('/home'); From ed58987075a1ac1461032123477a57c06c5f182a Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Sun, 21 Jan 2024 01:00:48 +0300 Subject: [PATCH 13/21] refactor: move functions over, remove some --- .gitignore | 1 + lib/src/components/supa_socials_auth.dart | 204 +++++++++++++++++++--- 2 files changed, 185 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index da66cc9..9e58663 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.txt # Miscellaneous *.class *.log diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index 4ebb320..b9fb72f 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -1,7 +1,11 @@ import 'dart:async'; +import 'dart:convert'; +import 'package:crypto/crypto.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:sign_in_with_apple/sign_in_with_apple.dart'; import 'package:supabase_auth_ui/src/utils/constants.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; @@ -58,13 +62,6 @@ enum SocialButtonVariant { iconAndText, } -// class NativeGoogleAuthConfig { -// GoogleNativeAuthConfig? google; -// bool enableNativeAppleAuth; - -// NativeGoogleAuthConfig({this.google, required this.enableNativeAppleAuth}); -// } - class NativeGoogleAuthConfig { /// Web Client ID and iOS Client ID that you registered with Google Cloud. /// Needed for Sign in with Google @@ -75,21 +72,12 @@ class NativeGoogleAuthConfig { {required this.webClientId, required this.iosClientId}); } -class GoogleNativeAuthConfig { - /// Web Client ID and iOS Client ID that you registered with Google Cloud. - /// Needed for Sign in with Google - String webClientId; - String iosClientId; - - GoogleNativeAuthConfig( - {required this.webClientId, required this.iosClientId}); -} - /// UI Component to create social login form class SupaSocialsAuth extends StatefulWidget { - /// Defines native auth providers to show in the form + /// Defines native google provider to show in the form final NativeGoogleAuthConfig? nativeGoogleAuthConfig; + /// Defines apple provider final bool? enableNativeAppleAuth; /// List of social providers to show in the form @@ -137,6 +125,123 @@ class SupaSocialsAuth extends StatefulWidget { class _SupaSocialsAuthState extends State { late final StreamSubscription _gotrueSubscription; + /// Performs Google sign in on Android and iOS + Future _googleSignIn(webClientId, iosClientId) async { + final GoogleSignIn googleSignIn = GoogleSignIn( + clientId: iosClientId, + serverClientId: webClientId, + ); + + final googleUser = await googleSignIn.signIn(); + final googleAuth = await googleUser!.authentication; + final accessToken = googleAuth.accessToken; + final idToken = googleAuth.idToken; + + if (accessToken == null) { + throw 'No Access Token found.'; + } + if (idToken == null) { + throw 'No ID Token found.'; + } + + return supabase.auth.signInWithIdToken( + provider: OAuthProvider.google, + idToken: idToken, + accessToken: accessToken, + ); + } + + /// Performs Apple sign in on iOS or macOS + Future _appleSignIn() async { + final rawNonce = supabase.auth.generateRawNonce(); + final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString(); + + final credential = await SignInWithApple.getAppleIDCredential( + scopes: [ + AppleIDAuthorizationScopes.email, + AppleIDAuthorizationScopes.fullName, + ], + nonce: hashedNonce, + ); + + final idToken = credential.identityToken; + if (idToken == null) { + throw const AuthException( + 'Could not find ID Token from generated credential.'); + } + + return supabase.auth.signInWithIdToken( + provider: OAuthProvider.apple, + idToken: idToken, + nonce: rawNonce, + ); + } + + Widget _nativeAuthBtn( + {required Widget icon, + required String label, + Color? bgColor, + Color? textColor, + required Future Function() signInMethod}) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), + child: widget.socialButtonVariant == SocialButtonVariant.icon + ? Material( + shape: const CircleBorder(), + elevation: 2, + color: bgColor, + child: InkResponse( + radius: 24, + onTap: () async { + try { + await signInMethod(); + } on AuthException catch (error) { + if (widget.onError == null && context.mounted) { + context.showErrorSnackBar(error.message); + } else { + widget.onError?.call(error); + } + } catch (error) { + if (widget.onError == null && context.mounted) { + context.showErrorSnackBar( + 'Unexpected error has occurred: $error'); + } else { + widget.onError?.call(error); + } + } + }, + child: SizedBox(height: 48, width: 48, child: icon), + ), + ) + : ElevatedButton.icon( + onPressed: () async { + try { + await signInMethod(); + } on AuthException catch (error) { + if (widget.onError == null && context.mounted) { + context.showErrorSnackBar(error.message); + } else { + widget.onError?.call(error); + } + } catch (error) { + if (widget.onError == null && context.mounted) { + context.showErrorSnackBar( + 'Unexpected error has occurred: $error'); + } else { + widget.onError?.call(error); + } + } + }, + icon: icon, + label: Text(label), + style: ElevatedButton.styleFrom( + backgroundColor: bgColor, + foregroundColor: textColor, + ), + ), + ); + } + @override void initState() { super.initState(); @@ -161,6 +266,8 @@ class _SupaSocialsAuthState extends State { @override Widget build(BuildContext context) { final providers = widget.socialProviders; + final googleAuthConfig = widget.nativeGoogleAuthConfig; + final isAppleAuth = widget.enableNativeAppleAuth == true; final coloredBg = widget.colored == true; if (providers.isEmpty) { @@ -293,11 +400,68 @@ class _SupaSocialsAuthState extends State { return widget.socialButtonVariant == SocialButtonVariant.icon ? Wrap( alignment: WrapAlignment.spaceEvenly, - children: authButtons, + children: [ + if (googleAuthConfig != null) + _nativeAuthBtn( + icon: Image.asset( + 'assets/logos/google_light.png', + package: 'supabase_auth_ui', + width: 48, + height: 48, + ), + label: 'Sign in with Google', + signInMethod: () => _googleSignIn( + googleAuthConfig!.webClientId, + googleAuthConfig.iosClientId, + ), + bgColor: const Color.fromRGBO(242, 242, 242, 1), + textColor: Colors.black, + ), + if (isAppleAuth) + _nativeAuthBtn( + icon: const Icon( + FontAwesomeIcons.apple, + color: Colors.white, + ), + label: 'Sign in with Apple', + signInMethod: _appleSignIn, + bgColor: Colors.black, + textColor: Colors.white, + ), + ...authButtons, + ], ) : Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: authButtons, + children: [ + if (googleAuthConfig != null) + _nativeAuthBtn( + icon: Image.asset( + 'assets/logos/google_light.png', + package: 'supabase_auth_ui', + width: 48, + height: 48, + ), + label: 'Sign in with Google', + signInMethod: () => _googleSignIn( + googleAuthConfig!.webClientId, + googleAuthConfig.iosClientId, + ), + bgColor: const Color.fromRGBO(242, 242, 242, 1), + textColor: Colors.black, + ), + if (isAppleAuth) + _nativeAuthBtn( + icon: const Icon( + FontAwesomeIcons.apple, + ), + label: 'Sign in with Apple', + signInMethod: _appleSignIn, + bgColor: Colors.black, + textColor: Colors.white, + ), + ...authButtons, + ], ); } } From 2af251be4696c6abf426af34a24ea9d8d3fde2e5 Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:45:24 +0300 Subject: [PATCH 14/21] delete original native auth file --- lib/src/components/supa_native_auth.dart | 205 ----------------------- 1 file changed, 205 deletions(-) delete mode 100644 lib/src/components/supa_native_auth.dart diff --git a/lib/src/components/supa_native_auth.dart b/lib/src/components/supa_native_auth.dart deleted file mode 100644 index 6cd6af2..0000000 --- a/lib/src/components/supa_native_auth.dart +++ /dev/null @@ -1,205 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'dart:convert'; -import 'package:crypto/crypto.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:sign_in_with_apple/sign_in_with_apple.dart'; -import 'package:supabase_auth_ui/src/utils/constants.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; - -class AuthType { - GoogleAuthType? google; - bool apple; - - AuthType({this.google, required this.apple}); -} - -class GoogleAuthType { - /// Web Client ID and iOS Client ID that you registered with Google Cloud. - /// Needed for Sign in with Google - String webClientId; - String iosClientId; - - GoogleAuthType({required this.webClientId, required this.iosClientId}); -} - -class SupaNativeAuth extends StatefulWidget { - /// Defines native auth providers to show in the form - final AuthType authType; - - /// Method to be called when the auth action is success - final void Function(Session) onSuccess; - - /// Method to be called when the auth action threw an excepction - final void Function(Object error)? onError; - - /// Whether to show a SnackBar after a successful sign in - final bool showSuccessSnackBar; - - const SupaNativeAuth({ - super.key, - required this.authType, - required this.onSuccess, - this.onError, - this.showSuccessSnackBar = true, - }); - - @override - State createState() => _SupaNativeAuthState(); -} - -class _SupaNativeAuthState extends State { - /// Performs Google sign in on Android and iOS - Future _googleSignIn(webClientId, iosClientId) async { - final GoogleSignIn googleSignIn = GoogleSignIn( - clientId: iosClientId, - serverClientId: webClientId, - ); - - final googleUser = await googleSignIn.signIn(); - final googleAuth = await googleUser!.authentication; - final accessToken = googleAuth.accessToken; - final idToken = googleAuth.idToken; - - if (accessToken == null) { - throw 'No Access Token found.'; - } - if (idToken == null) { - throw 'No ID Token found.'; - } - - return supabase.auth.signInWithIdToken( - provider: OAuthProvider.google, - idToken: idToken, - accessToken: accessToken, - ); - } - - /// Performs Apple sign in on iOS or macOS - Future _appleSignIn() async { - final rawNonce = supabase.auth.generateRawNonce(); - final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString(); - - final credential = await SignInWithApple.getAppleIDCredential( - scopes: [ - AppleIDAuthorizationScopes.email, - AppleIDAuthorizationScopes.fullName, - ], - nonce: hashedNonce, - ); - - final idToken = credential.identityToken; - if (idToken == null) { - throw const AuthException( - 'Could not find ID Token from generated credential.'); - } - - return supabase.auth.signInWithIdToken( - provider: OAuthProvider.apple, - idToken: idToken, - nonce: rawNonce, - ); - } - - Widget _nativeAuthBtn( - {required Widget icon, - required String label, - required Color bgColor, - required Color textColor, - required Future Function() signInMethod}) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), - child: ElevatedButton.icon( - onPressed: () async { - try { - await signInMethod(); - } on AuthException catch (error) { - if (widget.onError == null && context.mounted) { - context.showErrorSnackBar(error.message); - } else { - widget.onError?.call(error); - } - } catch (error) { - if (widget.onError == null && context.mounted) { - context - .showErrorSnackBar('Unexpected error has occurred: $error'); - } else { - widget.onError?.call(error); - } - } - }, - icon: icon, - label: Text(label), - style: ElevatedButton.styleFrom( - backgroundColor: bgColor, - foregroundColor: textColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(30), - ), - ), - ), - ); - } - - late final StreamSubscription _gotrueSubscription; - - @override - void initState() { - super.initState(); - _gotrueSubscription = - Supabase.instance.client.auth.onAuthStateChange.listen((data) { - final session = data.session; - if (session != null && mounted) { - widget.onSuccess.call(session); - if (widget.showSuccessSnackBar) { - context.showSnackBar('Successfully signed in!'); - } - } - }); - } - - @override - void dispose() { - super.dispose(); - _gotrueSubscription.cancel(); - } - - @override - Widget build(BuildContext context) { - final provider = widget.authType; - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (provider.google != null) - _nativeAuthBtn( - icon: Image.asset( - 'assets/logos/google_light.png', - package: 'supabase_auth_ui', - width: 36, - height: 36, - ), - label: 'Sign in with Google', - signInMethod: () => _googleSignIn( - provider.google!.webClientId, - provider.google!.iosClientId, - ), - bgColor: const Color.fromRGBO(242, 242, 242, 1), - textColor: Colors.black, - ), - if (provider.apple) - _nativeAuthBtn( - icon: const Icon( - FontAwesomeIcons.apple, - ), - label: 'Sign in with Apple', - signInMethod: _appleSignIn, - bgColor: Colors.black, - textColor: Colors.white, - ), - ], - ); - } -} From 83e87d84a9e7187e3cf33d59ce6c0afec9d3cbdd Mon Sep 17 00:00:00 2001 From: Fatuma Abdullahi <67555014+FatumaA@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:02:13 +0300 Subject: [PATCH 15/21] Update lib/src/components/supa_socials_auth.dart Co-authored-by: Tyler --- lib/src/components/supa_socials_auth.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index b9fb72f..032add1 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -65,8 +65,8 @@ enum SocialButtonVariant { class NativeGoogleAuthConfig { /// Web Client ID and iOS Client ID that you registered with Google Cloud. /// Needed for Sign in with Google - String webClientId; - String iosClientId; + final String webClientId; + final String iosClientId; NativeGoogleAuthConfig( {required this.webClientId, required this.iosClientId}); From e7ed6779f19c073c5a1f9efc2385694c7d1187d4 Mon Sep 17 00:00:00 2001 From: Fatuma Abdullahi <67555014+FatumaA@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:02:30 +0300 Subject: [PATCH 16/21] Update lib/src/components/supa_socials_auth.dart Co-authored-by: Tyler --- lib/src/components/supa_socials_auth.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index 032add1..546e7cf 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -78,7 +78,7 @@ class SupaSocialsAuth extends StatefulWidget { final NativeGoogleAuthConfig? nativeGoogleAuthConfig; /// Defines apple provider - final bool? enableNativeAppleAuth; + final bool enableNativeAppleAuth; /// List of social providers to show in the form final List socialProviders; From 79cd120e0fe7623720164917d0421caf0393a79e Mon Sep 17 00:00:00 2001 From: Fatuma Abdullahi <67555014+FatumaA@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:04:07 +0300 Subject: [PATCH 17/21] Update lib/src/components/supa_socials_auth.dart Co-authored-by: Tyler --- lib/src/components/supa_socials_auth.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index 546e7cf..30a9bd2 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -108,7 +108,7 @@ class SupaSocialsAuth extends StatefulWidget { const SupaSocialsAuth({ Key? key, this.nativeGoogleAuthConfig, - this.enableNativeAppleAuth, + this.enableNativeAppleAuth = true, required this.socialProviders, this.colored = true, this.redirectUrl, From 092cc2a90baf1822d852c1ae6d350bcdeff5f44d Mon Sep 17 00:00:00 2001 From: FatumaA <67555014+FatumaA@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:16:29 +0300 Subject: [PATCH 18/21] remove export of deleted file --- lib/supabase_auth_ui.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/supabase_auth_ui.dart b/lib/supabase_auth_ui.dart index 60234c3..3799793 100644 --- a/lib/supabase_auth_ui.dart +++ b/lib/supabase_auth_ui.dart @@ -6,6 +6,5 @@ export 'src/components/supa_reset_password.dart'; export 'src/components/supa_socials_auth.dart'; export 'src/components/supa_phone_auth.dart'; export 'src/components/supa_verify_phone.dart'; -export 'src/components/supa_native_auth.dart'; export 'src/utils/supa_auth_action.dart'; export 'package:supabase_flutter/supabase_flutter.dart'; From dbf806ea23029ea0bb66fb36a5810e5b53794e8b Mon Sep 17 00:00:00 2001 From: dshukertjr Date: Tue, 23 Jan 2024 14:35:01 +0900 Subject: [PATCH 19/21] Minor code cleanup --- .../Flutter/GeneratedPluginRegistrant.swift | 4 + lib/src/components/supa_socials_auth.dart | 193 +++++------------- 2 files changed, 60 insertions(+), 137 deletions(-) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 92b6497..464810a 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,13 +6,17 @@ import FlutterMacOS import Foundation import app_links +import google_sign_in_ios import path_provider_foundation import shared_preferences_foundation +import sign_in_with_apple import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) + FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index 30a9bd2..951582e 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -1,7 +1,9 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:crypto/crypto.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:google_sign_in/google_sign_in.dart'; @@ -63,13 +65,20 @@ enum SocialButtonVariant { } class NativeGoogleAuthConfig { - /// Web Client ID and iOS Client ID that you registered with Google Cloud. - /// Needed for Sign in with Google - final String webClientId; - final String iosClientId; + /// Web Client ID that you registered with Google Cloud. + /// + /// Required to perform native Google Sign In on Android + final String? webClientId; + + /// iOS Client ID that you registered with Google Cloud. + /// + /// Required to perform native Google Sign In on iOS + final String? iosClientId; - NativeGoogleAuthConfig( - {required this.webClientId, required this.iosClientId}); + const NativeGoogleAuthConfig({ + this.webClientId, + this.iosClientId, + }); } /// UI Component to create social login form @@ -77,7 +86,7 @@ class SupaSocialsAuth extends StatefulWidget { /// Defines native google provider to show in the form final NativeGoogleAuthConfig? nativeGoogleAuthConfig; - /// Defines apple provider + /// Whether to use native Apple sign in on iOS and macOS final bool enableNativeAppleAuth; /// List of social providers to show in the form @@ -126,7 +135,10 @@ class _SupaSocialsAuthState extends State { late final StreamSubscription _gotrueSubscription; /// Performs Google sign in on Android and iOS - Future _googleSignIn(webClientId, iosClientId) async { + Future _nativeGoogleSignIn({ + required String? webClientId, + required String? iosClientId, + }) async { final GoogleSignIn googleSignIn = GoogleSignIn( clientId: iosClientId, serverClientId: webClientId, @@ -138,10 +150,12 @@ class _SupaSocialsAuthState extends State { final idToken = googleAuth.idToken; if (accessToken == null) { - throw 'No Access Token found.'; + throw const AuthException( + 'No Access Token found from Google sign in result.'); } if (idToken == null) { - throw 'No ID Token found.'; + throw const AuthException( + 'No ID Token found from Google sign in result.'); } return supabase.auth.signInWithIdToken( @@ -152,7 +166,7 @@ class _SupaSocialsAuthState extends State { } /// Performs Apple sign in on iOS or macOS - Future _appleSignIn() async { + Future _nativeAppleSignIn() async { final rawNonce = supabase.auth.generateRawNonce(); final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString(); @@ -167,7 +181,7 @@ class _SupaSocialsAuthState extends State { final idToken = credential.identityToken; if (idToken == null) { throw const AuthException( - 'Could not find ID Token from generated credential.'); + 'Could not find ID Token from generated Apple sign in credential.'); } return supabase.auth.signInWithIdToken( @@ -177,71 +191,6 @@ class _SupaSocialsAuthState extends State { ); } - Widget _nativeAuthBtn( - {required Widget icon, - required String label, - Color? bgColor, - Color? textColor, - required Future Function() signInMethod}) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), - child: widget.socialButtonVariant == SocialButtonVariant.icon - ? Material( - shape: const CircleBorder(), - elevation: 2, - color: bgColor, - child: InkResponse( - radius: 24, - onTap: () async { - try { - await signInMethod(); - } on AuthException catch (error) { - if (widget.onError == null && context.mounted) { - context.showErrorSnackBar(error.message); - } else { - widget.onError?.call(error); - } - } catch (error) { - if (widget.onError == null && context.mounted) { - context.showErrorSnackBar( - 'Unexpected error has occurred: $error'); - } else { - widget.onError?.call(error); - } - } - }, - child: SizedBox(height: 48, width: 48, child: icon), - ), - ) - : ElevatedButton.icon( - onPressed: () async { - try { - await signInMethod(); - } on AuthException catch (error) { - if (widget.onError == null && context.mounted) { - context.showErrorSnackBar(error.message); - } else { - widget.onError?.call(error); - } - } catch (error) { - if (widget.onError == null && context.mounted) { - context.showErrorSnackBar( - 'Unexpected error has occurred: $error'); - } else { - widget.onError?.call(error); - } - } - }, - icon: icon, - label: Text(label), - style: ElevatedButton.styleFrom( - backgroundColor: bgColor, - foregroundColor: textColor, - ), - ), - ); - } - @override void initState() { super.initState(); @@ -267,7 +216,7 @@ class _SupaSocialsAuthState extends State { Widget build(BuildContext context) { final providers = widget.socialProviders; final googleAuthConfig = widget.nativeGoogleAuthConfig; - final isAppleAuth = widget.enableNativeAppleAuth == true; + final isNativeAppleAuthEnabled = widget.enableNativeAppleAuth; final coloredBg = widget.colored == true; if (providers.isEmpty) { @@ -346,6 +295,33 @@ class _SupaSocialsAuthState extends State { onAuthButtonPressed() async { try { + // Check if native Google login should be performed + if (socialProvider == OAuthProvider.google) { + final webClientId = googleAuthConfig?.webClientId; + final iosClientId = googleAuthConfig?.iosClientId; + final shouldPerformNativeGoogleSignIn = + (webClientId != null && !kIsWeb && Platform.isAndroid) || + (iosClientId != null && !kIsWeb && Platform.isIOS); + if (shouldPerformNativeGoogleSignIn) { + await _nativeGoogleSignIn( + webClientId: webClientId, + iosClientId: iosClientId, + ); + return; + } + } + + // Check if native Apple login should be performed + if (socialProvider == OAuthProvider.apple) { + final shouldPerformNativeAppleSignIn = + (isNativeAppleAuthEnabled && !kIsWeb && Platform.isIOS) || + (isNativeAppleAuthEnabled && !kIsWeb && Platform.isMacOS); + if (shouldPerformNativeAppleSignIn) { + await _nativeAppleSignIn(); + return; + } + } + await supabase.auth.signInWithOAuth( socialProvider, redirectTo: widget.redirectUrl, @@ -400,68 +376,11 @@ class _SupaSocialsAuthState extends State { return widget.socialButtonVariant == SocialButtonVariant.icon ? Wrap( alignment: WrapAlignment.spaceEvenly, - children: [ - if (googleAuthConfig != null) - _nativeAuthBtn( - icon: Image.asset( - 'assets/logos/google_light.png', - package: 'supabase_auth_ui', - width: 48, - height: 48, - ), - label: 'Sign in with Google', - signInMethod: () => _googleSignIn( - googleAuthConfig!.webClientId, - googleAuthConfig.iosClientId, - ), - bgColor: const Color.fromRGBO(242, 242, 242, 1), - textColor: Colors.black, - ), - if (isAppleAuth) - _nativeAuthBtn( - icon: const Icon( - FontAwesomeIcons.apple, - color: Colors.white, - ), - label: 'Sign in with Apple', - signInMethod: _appleSignIn, - bgColor: Colors.black, - textColor: Colors.white, - ), - ...authButtons, - ], + children: authButtons, ) : Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (googleAuthConfig != null) - _nativeAuthBtn( - icon: Image.asset( - 'assets/logos/google_light.png', - package: 'supabase_auth_ui', - width: 48, - height: 48, - ), - label: 'Sign in with Google', - signInMethod: () => _googleSignIn( - googleAuthConfig!.webClientId, - googleAuthConfig.iosClientId, - ), - bgColor: const Color.fromRGBO(242, 242, 242, 1), - textColor: Colors.black, - ), - if (isAppleAuth) - _nativeAuthBtn( - icon: const Icon( - FontAwesomeIcons.apple, - ), - label: 'Sign in with Apple', - signInMethod: _appleSignIn, - bgColor: Colors.black, - textColor: Colors.white, - ), - ...authButtons, - ], + children: authButtons, ); } } From 07cc5ef783d80d7d62e7e50c5b10ee7f85bd464b Mon Sep 17 00:00:00 2001 From: dshukertjr Date: Tue, 23 Jan 2024 14:42:36 +0900 Subject: [PATCH 20/21] minor example cleanup --- example/lib/sign_in.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/lib/sign_in.dart b/example/lib/sign_in.dart index 5836361..407488c 100644 --- a/example/lib/sign_in.dart +++ b/example/lib/sign_in.dart @@ -57,9 +57,9 @@ class SignUp extends StatelessWidget { spacer, SupaSocialsAuth( colored: true, - nativeGoogleAuthConfig: NativeGoogleAuthConfig( - webClientId: '', - iosClientId: '', + nativeGoogleAuthConfig: const NativeGoogleAuthConfig( + webClientId: 'YOUR_WEB_CLIENT_ID', + iosClientId: 'YOUR_IOS_CLIENT_ID', ), enableNativeAppleAuth: false, socialProviders: OAuthProvider.values, From b2897dc0d10983c7fd02a0e126ed268776b2f2bb Mon Sep 17 00:00:00 2001 From: dshukertjr Date: Tue, 23 Jan 2024 15:45:28 +0900 Subject: [PATCH 21/21] Add variable name to onSuccess parameter --- lib/src/components/supa_socials_auth.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/components/supa_socials_auth.dart b/lib/src/components/supa_socials_auth.dart index 951582e..4cd96ef 100644 --- a/lib/src/components/supa_socials_auth.dart +++ b/lib/src/components/supa_socials_auth.dart @@ -106,7 +106,7 @@ class SupaSocialsAuth extends StatefulWidget { final String? redirectUrl; /// Method to be called when the auth action is success - final void Function(Session) onSuccess; + final void Function(Session session) onSuccess; /// Method to be called when the auth action threw an excepction final void Function(Object error)? onError;