-
Notifications
You must be signed in to change notification settings - Fork 51
chore(repo): fixed dogfooding google login #1269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Brazol
wants to merge
2
commits into
main
Choose a base branch
from
fix/dogfooding-login-fixes
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| import 'dart:async'; | ||
| import 'dart:math' as math; | ||
|
|
||
| import 'package:firebase_auth/firebase_auth.dart' as fb; | ||
| import 'package:flutter/foundation.dart'; | ||
| import 'package:flutter/material.dart'; | ||
| import 'package:flutter_svg/flutter_svg.dart'; | ||
|
|
@@ -28,48 +29,120 @@ class LoginScreen extends StatefulWidget { | |
|
|
||
| class _LoginScreenState extends State<LoginScreen> { | ||
| final _appPreferences = locator<AppPreferences>(); | ||
| final _emailController = TextEditingController(); | ||
| final _usernameController = TextEditingController(); | ||
|
|
||
| Future<void> _loginWithGoogle() async { | ||
| final googleService = locator<GoogleSignIn>(); | ||
| StreamSubscription<GoogleSignInAuthenticationEvent>? _googleAuthSubscription; | ||
| bool _isLoggingIn = false; | ||
|
|
||
| @override | ||
| void initState() { | ||
| super.initState(); | ||
| unawaited(_initGoogleSignIn()); | ||
| } | ||
|
|
||
| /// Subscribes to Google auth events so the result of the mobile/macOS | ||
| /// `authenticate()` call is handled. Web uses Firebase Auth's popup flow | ||
| /// instead (see [_loginWithGoogleWeb]), so there is no google_sign_in plugin | ||
| /// to subscribe to there. | ||
| Future<void> _initGoogleSignIn() async { | ||
| if (kIsWeb) return; | ||
|
|
||
| final googleService = await locator.getAsync<GoogleSignIn>(); | ||
| _googleAuthSubscription = googleService.authenticationEvents.listen( | ||
| _handleGoogleAuthEvent, | ||
| onError: (Object e) { | ||
| debugPrint('Google auth event error: $e'); | ||
| _showSnackBar('Google sign-in failed: $e'); | ||
| }, | ||
| ); | ||
| } | ||
|
|
||
| void _handleGoogleAuthEvent(GoogleSignInAuthenticationEvent event) { | ||
| if (event is! GoogleSignInAuthenticationEventSignIn) return; | ||
|
|
||
| final googleUser = event.user; | ||
| unawaited( | ||
| _completeGoogleLogin( | ||
| email: googleUser.email, | ||
| name: googleUser.displayName ?? '', | ||
| image: googleUser.photoUrl, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| GoogleSignInAccount? googleUser; | ||
| /// Triggers an interactive Google sign-in from the button tap. | ||
| Future<void> _loginWithGoogle() async { | ||
| try { | ||
| googleUser = await googleService.attemptLightweightAuthentication(); | ||
| if (kIsWeb) { | ||
| await _loginWithGoogleWeb(); | ||
| return; | ||
| } | ||
|
|
||
| final googleService = await locator.getAsync<GoogleSignIn>(); | ||
| if (googleService.supportsAuthenticate()) { | ||
| // Result delivered via authenticationEvents -> _handleGoogleAuthEvent. | ||
| await googleService.authenticate(); | ||
| } | ||
| } catch (e) { | ||
| debugPrint('Google lightweight auth failed: $e'); | ||
| debugPrint('Google sign-in failed: $e'); | ||
| _showSnackBar('Google sign-in failed: $e'); | ||
| } | ||
| } | ||
|
|
||
| if (googleUser == null && googleService.supportsAuthenticate()) { | ||
| try { | ||
| googleUser = await googleService.authenticate(); | ||
| } catch (e) { | ||
| return debugPrint('Google sign-in failed: $e'); | ||
| /// Web Google sign-in via Firebase Auth's popup flow. | ||
| Future<void> _loginWithGoogleWeb() async { | ||
| try { | ||
| final provider = fb.GoogleAuthProvider() | ||
| // Hints Google to restrict the account chooser to the Stream domain. | ||
| ..setCustomParameters(const {'hd': 'getstream.io'}); | ||
|
|
||
| final credential = | ||
| await fb.FirebaseAuth.instance.signInWithPopup(provider); | ||
| final user = credential.user; | ||
| if (user == null) { | ||
| debugPrint('Google sign-in returned no user'); | ||
| _showSnackBar('Google sign-in failed: no user returned.'); | ||
| return; | ||
| } | ||
|
|
||
| await _completeGoogleLogin( | ||
| email: user.email, | ||
| name: user.displayName ?? '', | ||
| image: user.photoURL, | ||
| ); | ||
| } catch (e) { | ||
| debugPrint('Google sign-in failed: $e'); | ||
| _showSnackBar('Google sign-in failed: $e'); | ||
| } | ||
| } | ||
|
Brazol marked this conversation as resolved.
|
||
|
|
||
| if (googleUser == null) { | ||
| return debugPrint('Google login cancelled or unavailable'); | ||
| Future<void> _completeGoogleLogin({ | ||
| required String? email, | ||
| required String name, | ||
| String? image, | ||
| }) async { | ||
| if (email == null || email.isEmpty) { | ||
| debugPrint('Google sign-in returned no email'); | ||
| _showSnackBar('Google sign-in failed: no email address returned.'); | ||
| return; | ||
| } | ||
|
|
||
| final userInfo = UserInfo( | ||
| role: 'admin', | ||
| id: createValidId(googleUser.email), | ||
| name: googleUser.displayName ?? '', | ||
| image: googleUser.photoUrl, | ||
| id: createValidId(email), | ||
| name: name, | ||
| image: image, | ||
| ); | ||
|
|
||
| return _login(User(info: userInfo), _appPreferences.environment); | ||
| await _login(User(info: userInfo), _appPreferences.environment); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| Future<void> _loginWithEmail() async { | ||
| final email = _emailController.text; | ||
| if (email.isEmpty) return debugPrint('Email is empty'); | ||
| Future<void> _loginWithUsername() async { | ||
| final username = _usernameController.text; | ||
| if (username.isEmpty) return debugPrint('Username is empty'); | ||
|
|
||
| final userInfo = UserInfo( | ||
| role: 'admin', | ||
| id: createValidId(email), | ||
| name: email, | ||
| id: createValidId(username), | ||
| name: username, | ||
| ); | ||
|
|
||
| return _login(User(info: userInfo), _appPreferences.environment); | ||
|
|
@@ -78,7 +151,6 @@ class _LoginScreenState extends State<LoginScreen> { | |
| Future<void> _loginAsGuest() async { | ||
| final userId = randomId(size: 6); | ||
| final userInfo = UserInfo( | ||
| role: 'admin', | ||
| id: userId, | ||
| name: userId, | ||
| image: | ||
|
|
@@ -92,6 +164,9 @@ class _LoginScreenState extends State<LoginScreen> { | |
| } | ||
|
|
||
| Future<void> _login(User user, Environment environment) async { | ||
| if (_isLoggingIn) return; | ||
| _isLoggingIn = true; | ||
|
|
||
| if (mounted) unawaited(showLoadingIndicator(context)); | ||
|
|
||
| // Register StreamVideo client with the user. | ||
|
|
@@ -100,21 +175,27 @@ class _LoginScreenState extends State<LoginScreen> { | |
| try { | ||
| await authController.login(user, environment); | ||
| } catch (e, _) { | ||
| if (mounted) { | ||
| hideLoadingIndicator(context); | ||
| ScaffoldMessenger.of(context).showSnackBar( | ||
| SnackBar( | ||
| duration: const Duration(seconds: 20), | ||
| content: Text('Error: $e'), | ||
| ), | ||
| ); | ||
| } | ||
| if (mounted) hideLoadingIndicator(context); | ||
| _showSnackBar('Error: $e'); | ||
| } finally { | ||
| _isLoggingIn = false; | ||
| } | ||
| } | ||
|
|
||
| void _showSnackBar(String message) { | ||
| if (!mounted) return; | ||
| ScaffoldMessenger.of(context).showSnackBar( | ||
| SnackBar( | ||
| duration: const Duration(seconds: 20), | ||
| content: Text(message), | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| @override | ||
| void dispose() { | ||
| _emailController.dispose(); | ||
| unawaited(_googleAuthSubscription?.cancel()); | ||
| _usernameController.dispose(); | ||
| super.dispose(); | ||
| } | ||
|
|
||
|
|
@@ -131,6 +212,8 @@ class _LoginScreenState extends State<LoginScreen> { | |
| if (!kIsProd) | ||
| EnvironmentSwitcher( | ||
| currentEnvironment: _appPreferences.environment, | ||
| // Rebuild so the Google button visibility tracks the environment. | ||
| onEnvironmentChanged: (_) => setState(() {}), | ||
| ), | ||
| ], | ||
| ), | ||
|
|
@@ -162,12 +245,12 @@ class _LoginScreenState extends State<LoginScreen> { | |
| Padding( | ||
| padding: const EdgeInsets.symmetric(horizontal: 16), | ||
| child: TextField( | ||
| controller: _emailController, | ||
| controller: _usernameController, | ||
| style: theme.textTheme.bodyMedium?.apply( | ||
| color: Colors.white, | ||
| ), | ||
| decoration: const InputDecoration( | ||
| labelText: 'Enter Email', | ||
| labelText: 'Enter Username', | ||
| isDense: true, | ||
| border: OutlineInputBorder(), | ||
|
Comment on lines
-170
to
255
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good to add an errorText like here: https://github.com/GetStream/stream-video-flutter/pull/1272/changes#diff-c37bf48e33cc1417b6d455379a1f104f36a39271578670c5c35a01bda1d67d2eR184-R186 Currently we only do a |
||
| ), | ||
|
|
@@ -177,12 +260,12 @@ class _LoginScreenState extends State<LoginScreen> { | |
| Padding( | ||
| padding: const EdgeInsets.symmetric(horizontal: 16), | ||
| child: StreamButton.active( | ||
| label: 'Sign up with email', | ||
| label: 'Sign up with username', | ||
| icon: const Icon( | ||
| Icons.email_outlined, | ||
| Icons.person_outline, | ||
| color: Colors.white, | ||
| ), | ||
| onPressed: _loginWithEmail, | ||
| onPressed: _loginWithUsername, | ||
| ), | ||
| ), | ||
| const SizedBox(height: 16), | ||
|
|
@@ -203,11 +286,15 @@ class _LoginScreenState extends State<LoginScreen> { | |
| ], | ||
| ), | ||
| ), | ||
| const SizedBox(height: 16), | ||
| Padding( | ||
| padding: const EdgeInsets.symmetric(horizontal: 16), | ||
| child: GoogleLoginButton(onPressed: _loginWithGoogle), | ||
| ), | ||
| // Google (Stream employee) sign-in is only available on | ||
| // Pronto environments. | ||
| if (_appPreferences.environment.isPronto) ...[ | ||
| const SizedBox(height: 16), | ||
| Padding( | ||
| padding: const EdgeInsets.symmetric(horizontal: 16), | ||
| child: GoogleLoginButton(onPressed: _loginWithGoogle), | ||
| ), | ||
| ], | ||
| const SizedBox(height: 16), | ||
| Padding( | ||
| padding: const EdgeInsets.symmetric(horizontal: 16), | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.