-
Notifications
You must be signed in to change notification settings - Fork 69
Fix Issue #369: Implement automatic login redirect after successful signup #371
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
base: develop
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -28,31 +28,76 @@ class AuthenticationBloc | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _mapAppStartedToState( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AuthenticationEvent event, Emitter<AuthenticationState> emit) async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final (userLoggedIn, user) = await _authRepository.getUser(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log('User: $userLoggedIn, $user'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (userLoggedIn && user != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Authenticated(user.toEntity())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (userLoggedIn && user == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(OnboardingIncomplete()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Unauthenticated()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int retries = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const maxRetries = 3; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const retryDelay = Duration(milliseconds: 300); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (retries < maxRetries) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final (userLoggedIn, user) = await _authRepository.getUser(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log('User: $userLoggedIn, $user (attempt ${retries + 1})'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (userLoggedIn && user != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Authenticated(user.toEntity())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (userLoggedIn && user == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (retries == maxRetries - 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(OnboardingIncomplete()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Unauthenticated()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retries++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await Future.delayed(retryDelay); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Unauthenticated()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (_) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Unauthenticated()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _mapLoggedInToState( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AuthenticationEvent event, Emitter<AuthenticationState> emit) async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final (userLoggedIn, user) = await _authRepository.getUser(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (userLoggedIn && user != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Authenticated(user.toEntity())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (userLoggedIn && user == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(OnboardingIncomplete()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Unauthenticated()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int retries = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const maxRetries = 3; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const retryDelay = Duration(milliseconds: 300); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while (retries < maxRetries) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| final (userLoggedIn, user) = await _authRepository.getUser(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (userLoggedIn && user != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Authenticated(user.toEntity())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (userLoggedIn && user == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (retries == maxRetries - 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(OnboardingIncomplete()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Unauthenticated()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retries++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await Future.delayed(retryDelay); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| emit(Unauthenticated()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+71
to
101
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. π οΈ Refactor suggestion Apply the same refactoring to avoid code duplication. This method has identical retry logic to _mapLoggedInToState(
AuthenticationEvent event, Emitter<AuthenticationState> emit) async {
- // ... existing retry logic
+ await _handleAuthenticationCheck(emit);
}This also removes the need for try-catch here since the extracted method handles the authentication logic, and any unexpected errors would bubble up appropriately. π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _mapLogOutToState( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -99,6 +99,11 @@ class LoginRegisterBloc extends Bloc<LoginRegisterEvent, LoginRegisterState> { | |||||||||||||||||||||||
| emit(LoginRegisterLoading()); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| final map = await _authRepository.signInWithGoogle(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Add delay before updating authentication state | ||||||||||||||||||||||||
| await Future.delayed(const Duration(milliseconds: 200)); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Then update authentication state | ||||||||||||||||||||||||
| _authenticationBloc.add(LoggedIn()); | ||||||||||||||||||||||||
|
Comment on lines
+102
to
107
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. π οΈ Refactor suggestion Reconsider the fixed delay approach for state synchronization. The 200ms delay before updating authentication state is a brittle approach to handle data consistency. This could lead to issues in varying network conditions and doesn't guarantee that Firestore operations have completed. Consider these more robust alternatives:
- // Add delay before updating authentication state
- await Future.delayed(const Duration(milliseconds: 200));
-
- // Then update authentication state
+ // Update authentication state immediately - let AuthenticationBloc handle retries
_authenticationBloc.add(LoggedIn());The AuthenticationBloc already has retry logic, so the delays here might be redundant. π€ Prompt for AI Agents |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if (map['isNewUser'] as bool) { | ||||||||||||||||||||||||
|
|
@@ -108,8 +113,6 @@ class LoginRegisterBloc extends Bloc<LoginRegisterEvent, LoginRegisterState> { | |||||||||||||||||||||||
| user: map['user'] as UserModel)); | ||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||
| UserModel? user = map['user'] as UserModel; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| _authenticationBloc.add(LoggedIn()); | ||||||||||||||||||||||||
| emit(SigninWithGoogleSuccess(isNewUser: false, user: user)); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||
|
|
@@ -140,8 +143,14 @@ class LoginRegisterBloc extends Bloc<LoginRegisterEvent, LoginRegisterState> { | |||||||||||||||||||||||
| username: event.username, | ||||||||||||||||||||||||
| profilePictureUrl: url); | ||||||||||||||||||||||||
| if (user != null) { | ||||||||||||||||||||||||
| emit(SignUpSuccess(user)); | ||||||||||||||||||||||||
| // First wait for a delay to ensure Firestore propagation | ||||||||||||||||||||||||
| await Future.delayed(const Duration(milliseconds: 200)); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Then add the LoggedIn event | ||||||||||||||||||||||||
| _authenticationBloc.add(LoggedIn()); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Then emit SignUpSuccess | ||||||||||||||||||||||||
| emit(SignUpSuccess(user)); | ||||||||||||||||||||||||
|
Comment on lines
+146
to
+153
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. π οΈ Refactor suggestion Same timing concern applies to the signup flow. The fixed 200ms delay approach has the same reliability issues as mentioned in the Google signin flow. The comment mentions "Firestore propagation" but this doesn't guarantee the operation has completed. Since the repository's - // First wait for a delay to ensure Firestore propagation
- await Future.delayed(const Duration(milliseconds: 200));
-
- // Then add the LoggedIn event
+ // Add the LoggedIn event - AuthenticationBloc will handle retries
_authenticationBloc.add(LoggedIn());
-
- // Then emit SignUpSuccess
emit(SignUpSuccess(user));π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||
| emit(const SignUpFailed(message: 'Failed to sign up')); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Improve the retry mechanism implementation.
The retry logic is a good approach for handling eventual consistency issues, but there are opportunities for improvement:
_mapAppStartedToStateand_mapLoggedInToStateExtract the retry logic into a private method:
Then simplify both methods:
_mapAppStartedToState( AuthenticationEvent event, Emitter<AuthenticationState> emit) async { try { - // ... existing retry logic + await _handleAuthenticationCheck(emit, logAttempts: true); } catch (_) { emit(Unauthenticated()); } }π Committable suggestion
π€ Prompt for AI Agents