113 lines
3.2 KiB
Dart
113 lines
3.2 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'auth_service.dart';
|
|
import 'auth_state.dart';
|
|
import 'auth_user.dart';
|
|
|
|
/// Provider for the underlying AuthService instance.
|
|
/// Can be overridden in tests with a mock or fake AuthService.
|
|
final authServiceProvider = Provider<AuthService>((ref) {
|
|
final service = FirebaseAuthService();
|
|
ref.onDispose(() => service.dispose());
|
|
return service;
|
|
});
|
|
|
|
/// Reactive StateNotifier managing the authentication state for the UI
|
|
class AuthNotifier extends StateNotifier<AuthState> {
|
|
final AuthService _authService;
|
|
StreamSubscription<AuthState>? _subscription;
|
|
|
|
AuthNotifier(this._authService) : super(_authService.currentState) {
|
|
_subscription = _authService.authStateChanges.listen((state) {
|
|
this.state = state;
|
|
});
|
|
}
|
|
|
|
Future<void> signInWithEmailAndPassword(String email, String password) async {
|
|
await _authService.signInWithEmailAndPassword(email, password);
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> createUserWithEmailAndPassword(
|
|
String email,
|
|
String password, {
|
|
String? displayName,
|
|
}) async {
|
|
await _authService.createUserWithEmailAndPassword(
|
|
email,
|
|
password,
|
|
displayName: displayName,
|
|
);
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> signInWithGoogle() async {
|
|
await _authService.signInWithGoogle();
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> signInAnonymously() async {
|
|
await _authService.signInAnonymously();
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> sendPasswordResetEmail(String email) async {
|
|
await _authService.sendPasswordResetEmail(email);
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> sendEmailVerification() async {
|
|
await _authService.sendEmailVerification();
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> reloadCurrentUser() async {
|
|
await _authService.reloadCurrentUser();
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> reauthenticate({String? password}) =>
|
|
_authService.reauthenticate(password: password);
|
|
|
|
Future<void> deleteCurrentUser() async {
|
|
await _authService.deleteCurrentUser();
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
Future<void> signOut() async {
|
|
await _authService.signOut();
|
|
state = _authService.currentState;
|
|
}
|
|
|
|
void clearError() {
|
|
state = state.copyWith(clearError: true);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_subscription?.cancel();
|
|
super.dispose();
|
|
}
|
|
}
|
|
|
|
/// Primary Riverpod provider for UI reactivity on authentication
|
|
final authNotifierProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
|
|
final service = ref.watch(authServiceProvider);
|
|
return AuthNotifier(service);
|
|
});
|
|
|
|
/// Convenience provider returning the active AuthUser or null
|
|
final currentUserProvider = Provider<AuthUser?>((ref) {
|
|
return ref.watch(authNotifierProvider).user;
|
|
});
|
|
|
|
/// Convenience provider returning whether a non-anonymous user is signed in
|
|
final isAuthenticatedProvider = Provider<bool>((ref) {
|
|
return ref.watch(authNotifierProvider).isAuthenticated;
|
|
});
|
|
|
|
/// Convenience provider returning whether the user is in anonymous/local mode
|
|
final isAnonymousUserProvider = Provider<bool>((ref) {
|
|
return ref.watch(authNotifierProvider).isAnonymous;
|
|
});
|