Skip to content

Commit

Permalink
feat: adds sign out and uses BehaviorSubject for the user stream (#448)
Browse files Browse the repository at this point in the history
  • Loading branch information
AyadLaouissi authored May 8, 2024
1 parent facb6c6 commit 16bd3e2
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import 'dart:async';

import 'package:authentication_repository/authentication_repository.dart';
import 'package:firebase_auth/firebase_auth.dart' as fb;
import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart';

/// {@template authentication_repository}
/// Repository to manage authentication.
Expand All @@ -11,10 +13,13 @@ class AuthenticationRepository {
AuthenticationRepository({
fb.FirebaseAuth? firebaseAuth,
}) : _firebaseAuth = firebaseAuth ?? fb.FirebaseAuth.instance,
_userController = StreamController<User>.broadcast();
userController = BehaviorSubject<User>();

final fb.FirebaseAuth _firebaseAuth;
final StreamController<User> _userController;

/// [BehaviorSubject] with the [User].
@visibleForTesting
final BehaviorSubject<User> userController;
StreamSubscription<fb.User?>? _firebaseUserSubscription;

/// Stream of [User] which will emit the current user when
Expand All @@ -24,12 +29,12 @@ class AuthenticationRepository {
Stream<User> get user {
_firebaseUserSubscription ??=
_firebaseAuth.authStateChanges().listen((firebaseUser) {
_userController.add(
userController.add(
firebaseUser?.toUser ?? User.unauthenticated,
);
});

return _userController.stream;
return userController.stream;
}

/// Stream of id tokens that can be used to authenticate with Firebase.
Expand All @@ -51,16 +56,25 @@ class AuthenticationRepository {
Future<void> signInAnonymously() async {
try {
final userCredential = await _firebaseAuth.signInAnonymously();
_userController.add(userCredential.toUser);
userController.add(userCredential.toUser);
} on Exception catch (error, stackTrace) {
throw AuthenticationException(error, stackTrace);
}
}

/// Sign in the user anonymously.
///
/// If the sign in fails, an [AuthenticationException] is thrown.
Future<void> signOut() async {
await _firebaseAuth.signOut();

userController.add(User.unauthenticated);
}

/// Disposes any internal resources.
void dispose() {
_firebaseUserSubscription?.cancel();
_userController.close();
userController.close();
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/authentication_repository/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.1.8
rxdart: ^0.27.7

dev_dependencies:
flutter_test:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,30 @@ void main() {
});
});

group('signOut', () {
test('calls signOut on FirebaseAuth', () async {
when(() => firebaseAuth.signOut()).thenAnswer((_) async {});

await authenticationRepository.signOut();
verify(() => firebaseAuth.signOut()).called(1);
});

test('updates user with unauthenticated', () async {
when(() => firebaseAuth.signOut()).thenAnswer((_) async {});

await authenticationRepository.signOut();

await expectLater(
authenticationRepository.userController.stream,
emitsInOrder(
<User>[
User.unauthenticated,
],
),
);
});
});

group('dispose', () {
test('cancels internal subscriptions', () async {
final controller = StreamController<fb.User>();
Expand Down

0 comments on commit 16bd3e2

Please sign in to comment.