A value of type 'Stream<User?>' can't be returned from the function 'user' because it has a return type of 'Stream<User>?' - flutter

I am getting red line on auth.authStateChanges(),
Error says : A value of type 'Stream<User?>' can't be returned from the function 'user' because it has a return type of 'Stream?'.
class Auth {
final FirebaseAuth auth;
Auth({required this.auth});
Stream<User>? get user => auth.authStateChanges(); <-- here
Update now i get this error:
Future<String?> createAccount({required String email, required String password}) async {
try {
await auth.createUserWithEmailAndPassword( <-- here **auth**
email: email.trim(),
password: password.trim(),
);
return "Success";
} on FirebaseAuthException catch (e) {
return e.message;
} catch (e) {
rethrow;
}
}

Here is your updated class
import 'package:firebase_auth/firebase_auth.dart';
class Auth {
final FirebaseAuth auth;
Auth({required this.auth});
Stream<User?> get user => auth.authStateChanges();
Future<String?> createAccount({required String email, required String password}) async {
try {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email.trim(),
password: password.trim(),
);
return "Success";
} on FirebaseAuthException catch (e) {
return e.message;
} catch (e) {
rethrow;
}
}
}

Related

Flutter FirebaseAuth unit testing

I'm trying to test my whole AuthManager class which use FirebaseAuth to signin, login. Here my file:
class AuthManager extends ChangeNotifier {
final FirebaseAuth auth;
Stream<User?> get user => auth.authStateChanges();
static Future<FirebaseApp> initializeFirebase({
required BuildContext context,
}) async {
FirebaseApp firebaseApp = await Firebase.initializeApp();
return firebaseApp;
}
AuthManager({required this.auth});
Future<String> signup(String email, String password) async {
try {
final credential = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
return "Success";
} on FirebaseAuthException catch (e) {
rethrow;
}
}
Future<String> signInWithEmailAndPassword(
String email, String password) async {
try {
final userCredential = await auth.signInWithEmailAndPassword(
email: email, password: password);
return "Success";
} on FirebaseAuthException catch (e) {
return "Failed";
} catch (e) {
rethrow;
}
}
static Future<String> signOut() async {
try {
await FirebaseAuth.instance.signOut();
return "Success";
} catch (e) {
rethrow;
}
}
}
I used to return the usercredential but wanted to try test a simple string return for the test, following this tutorial: https://www.youtube.com/watch?v=4d6hEaUVvuU, here is my test file
import 'package:firebase_auth/firebase_auth.dart';
import 'package:notes_firebase_app/data/models/auth_manager.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
class MockFirebaseAuth extends Mock implements FirebaseAuth {
#override
Stream<User> authStateChanges() {
return Stream.fromIterable([
_mockUser,
]);
}
}
class MockUser extends Mock implements User {}
final MockUser _mockUser = MockUser();
class MockUserCredential extends Mock implements Future<UserCredential> {}
void main() {
final MockFirebaseAuth mockFirebaseAuth = MockFirebaseAuth();
final AuthManager authManager = AuthManager(auth: mockFirebaseAuth);
final MockUserCredential mockUserCredential = MockUserCredential();
setUp(() {});
test("emit occurs", () async {
expectLater(authManager.user, emitsInOrder([_mockUser]));
});
test("create account", () async {
when(mockFirebaseAuth.createUserWithEmailAndPassword(
email: "tadas#gmail.com", password: "123456"))
.thenAnswer((realInvocation) => null);
expect(
await authManager.signInWithEmailAndPassword(
"tadas#gmail.com", "123456"),
"Success");
});
}
I face two problems here, cannot pass null because we need to handle it now or this throw this error
The return type 'Null' isn't a 'Future<UserCredential>', as required by the closure's context
Then I tried to mock UserCredential like this.
final MockUserCredential mockUserCredential = MockUserCredential();
when(mockFirebaseAuth.createUserWithEmailAndPassword(
email: "tadas#gmail.com", password: "123456"))
.thenAnswer((realInvocation) => mockUserCredential);
but I'm getting this error:
type 'Null' is not a subtype of type 'Future<UserCredential>'
What am I doing wrong ? Help will be much appreciated.
I am not totally sure but mockito package may need a generator. Try mocktail package and use
when(()=> mockFirebaseAuth.createUserWithEmailAndPassword(
email: "tadas#gmail.com", password: "123456")).thenAnswer((realInvocation) => null);
use callback function in when().

How to get data from the CurrentUser on flutter Firebase Authentification

I have this Firebase Authentication Providers with who I can create an user, Sign In and Sign Out with the methods (only with email and password)
My problem I that in the UI I want to show data from the current User once the user has Sign In and I don't know how.
For example showing the email in a TextWidget or get the email as a variable for other stuff.
final firebaseAuthProvider = Provider<FirebaseAuth>((ref) {
return FirebaseAuth.instance;
});
class AuthenticationService {
final FirebaseAuth _firebaseAuth;
final Reader read;
AuthenticationService(this._firebaseAuth, this.read);
Stream<User?> get authStateChange => _firebaseAuth.authStateChanges();
Future<String> signIn({required String email, required String constrasena, required String nombreUsuario}) async {
try {
await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: constrasena,
);
return "Login Successful";
} on FirebaseAuthException catch (e) {
return e.message ?? 'Error';
}
}
Future<String> signUp({required String email, required String constrasena, required String nombreUsuario}) async {
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: constrasena,
);
read(addPerson(Person(nombre_de_usuario: nombreUsuario, email: email, videosVistos: 0)));
return "Signup Successful";
} on FirebaseAuthException catch (e) {
print(e.message);
return e.message ?? 'Error';
}
}
Future<void> signout() async {
await _firebaseAuth.signOut();
}
}
final authServicesProvider = Provider<AuthenticationService>((ref) {
return AuthenticationService(ref.read(firebaseAuthProvider), ref.read);
});
final authStateProvider = StreamProvider<User?>((ref) {
return ref.watch(authServicesProvider).authStateChange;
});
Thanks You!
You can use FirebaseAuth.instance.currentUser.
Example:
Get the user on your initState.
_user = FirebaseAuth.instance.currentUser;
And on your build method:
Text(_user?.email ?? 'No email')

Flutter can't catch exception after throw exception

I have func , after call function, I want to throw an ApiException, but I'nt catch it.
Step 1:
I'nt catch ApiException here
FutureOr<void> login({String? user, String? password}) async {
try {
emit(LoadingLoginState());
await loginUseCase?.login(user, password);
} on ApiException catch (e) { // I'nt catch ApiException here
emit(ErrorLoginState(errorMessage: e.errorMessage));
} catch (_) {
emit(ErrorLoginState(errorMessage: S.current.connectionProblem));
}
}
Step 2:
class LoginUseCase {
final LoginRepository _loginRepository;
LoginUseCase(this._loginRepository);
Future<LoginResponse?>? login(String? user, String? password) =>
_loginRepository.login(user, password);
}
Step 3:
abstract class LoginRepository{
Future<LoginResponse?>? login(String? user, String? password);
}
Step 4:
throw ApiException()
class UserRepoImpl implements LoginRepository {
UserApi? userApi;
UserRepoImpl({this.userApi});
#override
Future<LoginResponse?>? login(String? user, String? password) async {
throw ApiException();
}
}
To capture errors asynchroniously, you could use .catchError
callApi().catchError((error){
// handle exception here
});
Upd: your code
FutureOr<void> login({String? user, String? password}) async {
emit(LoadingLoginState());
await loginUseCase?.login(user, password)
?.catchError(error) {
if(error is ApiException) {
emit(ErrorLoginState(errorMessage: e.errorMessage));
} else {
emit(ErrorLoginState(errorMessage: S.current.connectionProblem));
}
}
}
Try wrapping the concrete implementation with a try-catch block like this:
class LoginUseCase {
final LoginRepository _loginRepository;
LoginUseCase(this._loginRepository);
Future<LoginResponse?>? login(String? user, String? password) {
try{
_loginRepository.login(user, password);
} on ApiException catch(e){
print('API Exception caught');
}
}
}

error: The argument type 'UserModel? Function(User?)' can't be assigned to the parameter type 'UserModel Function(User?)'

I am getting the following error in flutter.
UserModel is a class
class UserModel {
final String uid;
UserModel({this.uid});
}
And the code where this error is coming up is
Stream<UserModel> get user {
return _auth.authStateChanges()
.map(_userFromFirebaseUser);
}
Complete code:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
UserModel? _userFromFirebaseUser(User? user) {
return user != null ? UserModel(uid: user.uid) : null;
}
Stream<UserModel> get user {
return _auth.authStateChanges()
.map(_userFromFirebaseUser);
}
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User user = result.user!;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
Future signInWithEmailAndPassword( String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
User user = result.user!;
return _userFromFirebaseUser(user);
} catch(e){
print(e.toString());
return null;
}
}
Future signUpWithEmailAndPassword( String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user!;
return _userFromFirebaseUser(user);
} catch(e){
print(e.toString());
return null;
}
}
Future signOut() async {
try {
return await _auth.signOut();
} catch (e){
print(e.toString());
return null;
}
}
}
This is happening because your _userFromFirebaseUser is defined something like this,
UserModel? _userFromFirebaseUser(User? user) {
So this means that you are saying, your _userFromFirebaseUser might return a UserModel or might return a null.
One way to fix this is to make your getter return Stream<UserModel?> instead of Stream<UserModel>.
Stream<UserModel?> get user {
return _auth.authStateChanges()
.map(_userFromFirebaseUser);
}
Now your getter might return a UserModel or it might return a null.
I had the same problem and I'm glad I found the solution :
UserModel _userFromFirebase (User? user){
return UserModel(uid: user!.uid);
}
Stream<UserModel> get user{
return _auth.authStateChanges().map(_userFromFirebase);
}
and if _userFromFirebase appears error use:
_userFromFirebase(user.user) ;

'UserModel? Function(User)' cant be assigned to the parameter type 'UserModel Function(User?)' because 'UserModel?' is nullable and 'UserModel' isn't

#I've been following a youtube project for twitter clone and I get error when putting _userFromFirebaseUser in map();#
##I get error at time 13:29, here is the link. https://www.youtube.com/watch?v=YI7avcWI3aQ&t=919s ##
##The error that I received at the terminal is Launching lib\main.dart on sdk gphone x86 arm in debug mode...
lib\main.dart:1
lib/services/auth/auth.dart:13:40: Error: The argument type 'UserModel? Function(User)' can't be assigned to the parameter type 'UserModel Function(User?)' because 'UserModel?' is nullable and 'UserModel' isn't.
'UserModel' is from 'package:twitterclone/models/users.dart' ('lib/models/users.dart').
'User' is from 'package:firebase_auth/firebase_auth.dart' ('../../AppData/Local/Pub/Cache/hosted/pub.dartlang.org/firebase_auth-1.0.1/lib/firebase_auth.dart').
return auth.authStateChanges().map(_userFromFirebaseUser);
The code and the directories
-users.dart
class UserModel {
final String id;
UserModel({required this.id});
}
-auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:twitterclone/models/users.dart';
class AuthService {
FirebaseAuth auth = FirebaseAuth.instance;
UserModel? _userFromFirebaseUser(User user) {
// ignore: unnecessary_null_comparison
return user != null ? UserModel(id: user.uid) : null;
}
Stream<UserModel> get user {
return auth.authStateChanges().map(_userFromFirebaseUser);
}
Future<void> signUp(email, password) async {
try {
User user = (await auth.createUserWithEmailAndPassword(
email: email, password: password)) as User;
_userFromFirebaseUser(user);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
} catch (e) {
print(e);
}
}
Future<void> signIn(email, password) async {
try {
User user = (await auth.signInWithEmailAndPassword(
email: email, password: password)) as User;
_userFromFirebaseUser(user);
} on FirebaseAuthException catch (e) {
print(e);
} catch (e) {
print(e);
}
}
}
In
UserModel? _userFromFirebaseUser(User user) {
// ignore: unnecessary_null_comparison
return user != null ? UserModel(id: user.uid) : null;
}
Since UserModel is nullable, change the argument to be nullable also
UserModel? _userFromFirebaseUser(User? user) ...
Use This code:-
Stream<UserList?> get user {
return _auth
.authStateChanges()
.map((User? user) => _userFromFirebase(user!));
}
*UserList is class,
null safety!