Skip to content

Commit

Permalink
Updated to match firebase_auth v0.18.0
Browse files Browse the repository at this point in the history
  • Loading branch information
feinstein committed Aug 19, 2020
1 parent 545d72c commit 1f7b414
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 115 deletions.
2 changes: 1 addition & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Below is a list of people and organizations that have contributed
# to the FirebaseUser Stream project. Names should be added to the list like so:
# to the Firebase User Stream project. Names should be added to the list like so:
#
# Name/Organization <email address>

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.1.0-alpha
* Updated to match firebase_auth v0.18.0.

## 1.0.0

* First stable release.
Expand Down
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# FirebaseUser Stream
# Firebase User Stream

[![pub package](https://img.shields.io/pub/v/firebase_user_stream.svg)](https://pub.dartlang.org/packages/firebase_user_stream)

A Package for subscribing to FirebaseUser reload updates.
A Package for subscribing to User reload updates.

## The problem
# ATTENTION
Since `firebase_auth` version 0.18.0 this library is mostly pointless as `firebase_auth` (finally) adds
`authStateChanges()` which mostly substitutes this package, fixing the problem described below.

I mean mostly because here we can further functionality like: reloading based on a predicate, reload and get the user in
the same line, and have separate streams for authentication and user changes. Although that's not useful to most people.

## The (old, pre 0.18.0) problem
The FirebaseAuth Flutter plugin provides a `Stream<FirebaseUser>` with
`onAuthStateChanged`, which is useful for getting updates when a user signs-in
or signs-out, but it fails to provide an update when the user data itself changes.
Expand All @@ -14,8 +21,8 @@ address, in other words get if `FirebaseUser.isEmailVerified` changed its value,
this is updated server-side and not pushed to the app.

`FirebaseAuth.currentUser()` will only detect changes made locally to the user, but
if any changes are made server-side, it won't detect, unless `FirebaseUser.reload()`
is called first and then we need to call `FirebaseAuth.currentUser()` again to get
if any server-side changes occur, it won't detect them, unless `FirebaseUser.reload()`
is called first, then we need to call `FirebaseAuth.currentUser()` again to get
the reloaded user, but still this user won't be emitted by `onAuthStateChanged`.

## The solution
Expand Down Expand Up @@ -83,7 +90,7 @@ subscription.cancel();
```

You also can get the reloaded user as the return value of `reloadCurrentUser`, but in this case,
the predicate will be ignored and the reloaded user will always be returned.
the predicate will be ignored, and the reloaded user will always be returned.

```dart
var user = await FirebaseUserReloader.reloadCurrentUser();
Expand Down Expand Up @@ -113,8 +120,7 @@ Both `onAuthStateChangedOrReloaded` and `onUserReloaded` are broadcast streams.
This library uses `static` methods for easiness of usage, but this doesn't limit its
testability.

`FirebaseUserReloader` can be injected with a mocked instance of `FirebaseAuth`, which
can then be used for unit testing.
`FirebaseUserReloader` can be injected with a mocked instance of `FirebaseAuth` for unit testing.

For any examples on how to control its behavior under tests, please take a look at our
own tests inside the `test` folder.
2 changes: 1 addition & 1 deletion example/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ void main() {
});

FirebaseUserReloader.reloadCurrentUser();
FirebaseUserReloader.reloadCurrentUser((user) => user.isEmailVerified);
FirebaseUserReloader.reloadCurrentUser((user) => user.emailVerified);
}
52 changes: 29 additions & 23 deletions lib/firebase_user_stream.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,58 @@ import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:rxdart/rxdart.dart';

typedef EmissionPredicate = bool Function(FirebaseUser user);
typedef EmissionPredicate = bool Function(User user);

class FirebaseUserReloader {
static FirebaseAuth _auth = FirebaseAuth.instance;
static FirebaseAuth _auth;

static FirebaseAuth get auth {
if (_auth == null) {
_auth = FirebaseAuth.instance;
}

return _auth;
}

@visibleForTesting
static set auth(FirebaseAuth value) {
if (_auth != value) {
_auth = value;
_onAuthStateChangedOrReloaded =
_mergeWithOnUserReloaded(_auth.onAuthStateChanged);
_mergeWithOnUserReloaded(_auth.authStateChanges());
}
}

static FirebaseAuth get auth => _auth;

static final StreamController<FirebaseUser> _userReloadedStreamController =
StreamController<FirebaseUser>.broadcast();
static final StreamController<User> _userReloadedStreamController =
StreamController<User>.broadcast();

/// Receive a [FirebaseUser] each time the user is reloaded by
/// Receive a [User] each time the user is reloaded by
/// [reloadCurrentUser].
static Stream<FirebaseUser> get onUserReloaded =>
static Stream<User> get onUserReloaded =>
_userReloadedStreamController.stream;

static Stream<FirebaseUser> _onAuthStateChangedOrReloaded =
_mergeWithOnUserReloaded(_auth.onAuthStateChanged);
static Stream<User> _onAuthStateChangedOrReloaded =
_mergeWithOnUserReloaded(_auth.authStateChanges());

/// Receive [FirebaseUser] each time the user signIn, signOut or is reloaded
/// Receive [User] each time the user signIn, signOut or is reloaded
/// by [reloadCurrentUser].
static Stream<FirebaseUser> get onAuthStateChangedOrReloaded =>
static Stream<User> get onAuthStateChangedOrReloaded =>
_onAuthStateChangedOrReloaded;

/// Merges the given [Stream] with [onUserReloaded] as a broadcast [Stream].
static Stream<FirebaseUser> _mergeWithOnUserReloaded(Stream<FirebaseUser> stream) {
static Stream<User> _mergeWithOnUserReloaded(Stream<User> stream) {
return Rx.merge([stream, onUserReloaded]).publishValue()..connect();
}

/// Reloads the current [FirebaseUser], using an optional predicate to decide
/// if the reloaded [FirebaseUser] should be emitted by [onUserReloaded] or
/// not. If a predicate isn't provided the reloaded [FirebaseUser] will
/// Reloads the current [User], using an optional predicate to decide
/// if the reloaded [User] should be emitted by [onUserReloaded] or
/// not. If a predicate isn't provided the reloaded [User] will
/// always be emitted.
///
/// The reloaded [FirebaseUser] will always be returned, independently of the
/// The reloaded [User] will always be returned, independently of the
/// predicate's result.
///
/// Example for getting updates only when [FirebaseUser.isEmailVerified]
/// Example for getting updates only when [User.emailVerified]
/// is true:
///
/// ```dart
Expand All @@ -65,14 +71,14 @@ class FirebaseUserReloader {
///
/// // Calling this will print the user, if its email has been verified.
/// await FirebaseUserReloader.reloadCurrentUser(FirebaseAuth.instance,
/// (user) => user.isEmailVerified);
/// (user) => user.emailVerified);
/// ```
static Future<FirebaseUser> reloadCurrentUser(
static Future<User> reloadCurrentUser(
[EmissionPredicate predicate]) async {
FirebaseUser oldUser = await auth.currentUser();
User oldUser = auth.currentUser;
// we need to first reload to then get the updated data.
await oldUser.reload();
FirebaseUser newUser = await auth.currentUser();
User newUser = auth.currentUser;

if (predicate == null || predicate(newUser)) {
_userReloadedStreamController.add(newUser);
Expand Down
Loading

0 comments on commit 1f7b414

Please sign in to comment.