I am building an application, and I would like to show a progress bar while the user is waiting to be logged-in in the platform.
How can I add a circle progress bar while I am awaiting?
Future<void> validateAndSubmit() async {
if (validateAndSave()) {
try {
final Auth auth = await AuthFactory.getAuth();
final String userId = await auth
.signInWithEmailAndPassword(_email, _password)
.whenComplete(() =>
Navigator.of(context).popAndPushNamed(RootPage.routeName));
print('Signed In:$userId');
} catch (e) {
print('Error:$e');
print(e.toString());
}
}
}
Since you use future, the best way would be to control a CircularProgressIndicator() with a boolean inside your method like this:
Future<void> validateAndSubmit() async {
setState(( {
_isLoading = true;
});
if (validateAndSave()) {
try {
final Auth auth = await AuthFactory.getAuth();
final String userId = await auth
.signInWithEmailAndPassword(_email, _password)
.whenComplete(() =>
{
setState(() {
_isLoading = false;
});
Navigator.of(context).popAndPushNamed(RootPage.routeName));
}
print('Signed In:$userId');
} catch (e) {
print('Error:$e');
print(e.toString());
}
}
}
and then somewhere in your widget tree:
_isLoading ? CircularProgressIndicator() : Other widget...
Related
I'm working with emailJs flutter package and for some reason the code gets called just the first time after app launch. Subsequent calls to the function does nothing.
I need it to run as much as I call the function in the app
Here is the code
final EmailJS emailJS = EmailJS();
#override
void initState() {
super.initState();
getPermission().then((value) async {
void sendMail() async {
EmailJS.send(
'****',
'***',
{
'user_subject': 'From xenox forge',
'from': sender,
'message': sms,
'time': time,
'reply_to': 'email#mail'
},
Options(
publicKey: 'my key',
privateKey: 'my key',
),
);
}
if (value) {
_plugin.read();
_plugin.smsStream.listen((event) async {
sms = event.body;
sender = event.sender;
time = event.timeReceived.toString();
sendMail();
});
}
});
}
Future<bool> getPermission() async {
if (await Permission.sms.status == PermissionStatus.granted) {
return true;
} else {
if (await Permission.sms.request() == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
#override
void dispose() {
super.dispose();
_plugin.dispose();
}
i have been trying to solve this error , after i login i was getting type 'Null' is not a subtype of type 'String' for about 5 seconds and after that the app successfully login, i do not know why this happen, i already add null check to the User but i still get the error . Below is my code, tell me if you need more info, Thanks for helping
class _controState extends State<contro> {
_controState();
User? user = FirebaseAuth.instance.currentUser;
UserModel loggedInUser = UserModel();
var role;
var email;
var id;
#override
void initState() {
super.initState();
FirebaseFirestore.instance
.collection("users") //.where('uid', isEqualTo: user!.uid)
.doc(user!.uid)
.get()
.then((value) {
this.loggedInUser = UserModel.fromMap(value.data());
}).whenComplete(() {
CircularProgressIndicator();
setState(() {
email = loggedInUser.email.toString();
role = loggedInUser.role.toString();
id = loggedInUser.uid.toString();
});
});
}
routing() {
if (role == 'Freelancer') {
return JobScreen(
id: id,
);
} else {
return JobScreenClient(
id: id,
);
}
}
#override
Widget build(BuildContext context) {
CircularProgressIndicator();
return routing();
}
}
inside your routing, role might be null before FirebaseFirestore's result get ready, try this:
routing() {
if(role == null){
return Container(); // show empty widget like this or what widget you want
}else if (role == 'Freelancer') {
return JobScreen(
id: id,
);
} else {
return JobScreenClient(
id: id,
);
}
}
You have to add async/await to your code, because it's future functions..
void initState() async {
super.initState();
await FirebaseFirestore.instance
.collection("users") //.where('uid', isEqualTo: user!.uid)
.doc(user!.uid)
.get()
.then((value) {
this.loggedInUser = UserModel.fromMap(value.data());
}).whenComplete(() {
CircularProgressIndicator();
setState(() {
email = loggedInUser.email.toString();
role = loggedInUser.role.toString();
id = loggedInUser.uid.toString();
});
});
}
routing() {
if(role == null){
return const Center(child: CircularProgressIndicator());
}else if (role == 'Freelancer') {
return JobScreen(
id: id,
);
} else {
return JobScreenClient(
id: id,
);
}
}
In my Flutter App I'm using Firebase Auth to authenticate the users. I have login_service with Provider and in the main.dart I check the state of the login.
My flow is:
Check if the user is logged with trackUserState()
If the user is logged I check the database: if the user exist I go to the HomeScreen, if not to the registration screen
My problem is that where I'm checking if the user is logged or not (on the main.dart, inside the routes object) generates a problem: the function is being executed all the time, nonstop.
How can I refactor this to only execute the function on init and after that notify only the changes (logout, a logged but non registered user being registered...) with notifyListeners()?
This are the codes of both files, main.dart and login_service.dart:
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<LoginState>(
create: (context) => LoginState(),
child: MaterialApp(
title: 'MyApp',
debugShowCheckedModeBanner: false,
routes: {
// ignore: missing_return
'/': (BuildContext context) {
var state = Provider.of<LoginState>(context);
state.trackUserState();
if(state.userExist() == false) {
return RegisterScreen();
}
if(state.isLoggedIn() == true) {
return HomeScreen();
}
if (state.isLoggedIn() == false) {
return LoginScreen();
}
},
...here the other routes
},
theme: brightTheme,
),
);
}
}
login_service.dart
class LoginState with ChangeNotifier {
// Instances
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
// Variables
User _user;
bool _userExist;
bool _loading = false;
bool _isLoggedIn = false;
String _userEmail;
// Functions to track
bool isLoggedIn() => _isLoggedIn;
bool isLoading() => _loading;
bool userExist() => _userExist;
User currentUser() => _user;
String getUserEmail() => _userEmail;
// Registration Flow
void goAheadAfterRegistration() async {
if (_user != null) {
var userExist = await _firestore.collection('users').where('email', isEqualTo: _user.email).get();
if (userExist.docs.length == 1) {
} else {
print('Este user aun no se ha registrado');
_userExist = false;
}
notifyListeners();
} else {
_loading = false;
notifyListeners();
}
}
void checkUserOnDatabase() async {
var userExistOnDatabase = await _firestore.collection('users').where('email', isEqualTo: _user.email).get();
if (userExistOnDatabase.docs.length == 1) {
_isLoggedIn = true;
_userExist = true;
notifyListeners();
} else {
_userExist = false;
notifyListeners();
}
notifyListeners();
}
// LogOut the user
void logout() async {
_googleSignIn.signOut();
_auth.signOut();
_loading = false;
_isLoggedIn = false;
notifyListeners();
}
// Tracking the user state
void trackUserState() {
_auth.authStateChanges()
.listen((User user) {
if (user == null) {
_isLoggedIn = false;
notifyListeners();
} else {
_user = user;
checkUserOnDatabase();
notifyListeners();
}
});
}
// Third party login providers
void googleLogin() async {
_loading = true;
notifyListeners();
_user = await _handleSignIn();
checkUserOnDatabase();
}
Future<User> _handleSignIn() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final User user = (await _auth.signInWithCredential(credential)).user;
return user;
}
// TODO on login true circular progress indicator while we check if the user exist to prevent new logins
}
Thank you very much guys!
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
*handle all that 1 trigger stuff here*
runApp(
MyApp(),
);
}
I'm trying to test my firebase auth methods. Auth methods are signin, signout , register, etc.
this are methods i want to perform unit test.
I'm getting error No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
I tried to initialize Firebase.initializeApp in test main method its also doesn't work.
class MockUserRepository extends Mock implements AuthService {
final MockFirebaseAuth auth;
MockUserRepository({this.auth});
}
class MockFirebaseAuth extends Mock implements FirebaseAuth{}
class MockFirebaseUser extends Mock implements FirebaseUser{}
class MockFirebase extends Mock implements Firebase{}
void main() {
MockFirebase firebase=MockFirebase();
MockFirebaseAuth _auth = MockFirebaseAuth();
BehaviorSubject<MockFirebaseUser> _user = BehaviorSubject<MockFirebaseUser>();
when(_auth.onAuthStateChanged).thenAnswer((_){
return _user;
});
AuthService _repo = AuthService.instance(auth: _auth);
group('user repository test', (){
when(_auth.signInWithEmailAndPassword(email: "email",password: "password")).thenAnswer((_)async{
_user.add(MockFirebaseUser());
});
when(_auth.signInWithEmailAndPassword(email: "mail",password: "pass")).thenThrow((){
return null;
});
test("sign in with email and password", () async {
var signedIn = await _repo.onLogin(email:"testuser#test.com",password: "123456");
expect(signedIn, isNotNull);
expect(_repo.status, Status.Authenticated);
});
test("sing in fails with incorrect email and password",() async {
var signedIn = await _repo.onLogin(email:"testuser#test.com",password: "666666");
expect(signedIn, false);
expect(_repo.status, Status.Unauthenticated);
});
test('sign out', ()async{
await _repo.signout();
expect(_repo.status, Status.Unauthenticated);
});
});
}
AuthService class
enum Status { Uninitialized, Authenticated, Authenticating,
Unauthenticated }
class AuthService with ChangeNotifier {
FirebaseAuth auth = FirebaseAuth.instance;
FirebaseUser _user;
FirebaseUser get user => _user;
set user(FirebaseUser value) {
_user = value;
}
Status _status = Status.Uninitialized;
Future<User> getCurrentUser() async {
User currentUser;
await FirebaseAuth.instance.authStateChanges().listen((User user) {
currentUser = user;
});
return currentUser;
}
AuthService();
AuthService.instance({this.auth}) {
// auth.onAuthStateChanged.listen((user) {
// onAuthStateChanged(user);
// });
}
Future<void> signout() async {
await auth.signOut();
}
Future<User> createAccount({String email, String password}) async {
try {
UserCredential userCredential = await
auth.createUserWithEmailAndPassword(
email: email, password: password);
return userCredential != null ? userCredential.user : null;
} on FirebaseAuthException catch (e) {
showToast(e.message);
} catch (e) {
log(e.toString());
return null;
}
}
Future<User> onLogin({String email, String password}) async {
try {
User user;
await auth
.signInWithEmailAndPassword(email: email, password: password)
.then((value) {
showToast("Login sucessful");
user = value != null ? value.user : null;
});
return user;
} on FirebaseAuthException catch (e) {
showToast(e.message);
}
}
sendResetPassword({String email}) async {
bool isSent = false;
try {
await auth.sendPasswordResetEmail(email: email).then((value) {
showToast("Reset password email sent");
isSent = true;
});
return isSent;
} on FirebaseAuthException catch (e) {
showToast(e.message);
}
}
Future<void> onAuthStateChanged(FirebaseUser user) async {
if (user == null) {
_status = Status.Unauthenticated;
} else {
_user = user;
_status = Status.Authenticated;
}
notifyListeners();
}
Status get status => _status;
set status(Status value) {
_status = value;
}
}
Have a look at how they tested directly in firebase_auth code : https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_auth/firebase_auth/test
Call the setupFirebaseAuthMocks (you can adapt the code from here) method at the beginning of your main method and call await Firebase.initializeApp(); in a setUpAll method.
Firebase.initializeApp() is the solution for this. I am pretty sure. Try calling it in the file your are doing all these functions in their initState().
I was asked permission from the user in runtime but I need to ask MULTIPLE permissions for example phone, contact, SMS, etc so I'm stuck on that how to call this method one after another is there any way to ask after one permission completed another popup open?
import 'package:permission_handler/permission_handler.dart';
class PermissionService{
final PermissionHandler _permissionHandler = PermissionHandler();
Future<bool> _requestPermissionContact(PermissionGroup permission) async {
var result = await _permissionHandler.requestPermissions([permission]);
if (result[PermissionGroup.contacts] == PermissionStatus.granted) {
print("sfhalsjfhas fasdhufaiusfh aloifahdf oalsifu");
}
}
Future<bool> requestContactPermission({Function onPermissionDenied}) async {
var granted = await _requestPermissionContact(PermissionGroup.contacts);
if (!granted) {
onPermissionDenied();
}
return granted;
}
Future<bool> hasContactPermission() async {
return hasPermission(PermissionGroup.contacts);
}
Future<bool> _requestPermissionSms(PermissionGroup permission) async {
var result = await _permissionHandler.requestPermissions([permission]);
if (result[permission] == PermissionStatus.granted) {
print("sfhalsjfhas fasdhufaiusfh aloifahdf oalsifu");
return true;
}
return false;
}
Future<bool> requestSmsPermission({Function onPermissionDenied}) async {
var granted = await _requestPermissionSms(PermissionGroup.sms);
if (!granted) {
onPermissionDenied();
}
return granted;
}
Future<bool> hasSmsPermission() async {
_requestPermissionPhone(PermissionGroup.phone);
return hasPermission(PermissionGroup.sms);
}
Future<bool> _requestPermissionPhone(PermissionGroup permission) async {
var result = await _permissionHandler.requestPermissions([permission]);
if (result[permission] == PermissionStatus.granted) {
return true;
}
return false;
}
Future<bool> requestPhonePermission({Function onPermissionDenied}) async {
var granted = await _requestPermissionPhone(PermissionGroup.phone);
if (!granted) {
onPermissionDenied();
}
return granted;
}
Future<bool> hasPhonePermission() async {
return hasPermission(PermissionGroup.phone);
}
Future<bool> hasPermission(PermissionGroup permission) async {
var permissionStatus =
await _permissionHandler.checkPermissionStatus(permission);
return permissionStatus == PermissionStatus.granted;
}
}
this is my permission class i want to call this three permission and in initState i was called this like
#override
initState() {
permissionAcess();
permissionAcessSms();
permissionAcessPhone();
super.initState();
}
Future permissionAcess() {
PermissionService().requestContactPermission(onPermissionDenied: () {
print('Permission has been denied');
});
}
Future permissionAcessSms() {
PermissionService().requestSmsPermission(onPermissionDenied: () {
print('Permission has been denied');
});
}
Future permissionAcessPhone() {
PermissionService().requestPhonePermission(onPermissionDenied: () {
print('Permission has been denied');
});
}
but it called only one permission so how to call all these three permission in runtime?
yes you can ask multiple permission at same time just update your code like this
your PermissionServices file will be
import 'package:permission_handler/permission_handler.dart';
class PermissionService{
final PermissionHandler _permissionHandler = PermissionHandler();
Future<bool> _requestPermission() async {
var result = await _permissionHandler.requestPermissions([PermissionGroup.phone,PermissionGroup.contacts,PermissionGroup.sms]);
if (result == PermissionStatus.granted) {
return true;
}
return false;
}
Future<bool> requestPermission({Function onPermissionDenied}) async {
var granted = await _requestPermission();
if (!granted) {
onPermissionDenied();
}
return granted;
}
Future<bool> hasPhonePermission() async {
return hasPermission(PermissionGroup.phone);
}
Future<bool> hasPermission(PermissionGroup permission) async {
var permissionStatus =
await _permissionHandler.checkPermissionStatus(permission);
return permissionStatus == PermissionStatus.granted;
}
}
and your initState will be
#override
initState(){
permissionAcessPhone();
super.initState();
}
Future permissionAcessPhone() {
PermissionService().requestPermission(onPermissionDenied: () {
print('Permission has been denied');
});
}
In earliar version of permission handler we can hande multiple permission at a same time permission_handler 10.2.0
List<Permission> statuses = [
Permission.location,
Permission.camera,
Permission.sms,
Permission.storage,
];
Future<void> requestPermission() async {
try {
for (var element in statuses) {
if ((await element.status.isDenied ||
await element.status.isPermanentlyDenied)) {
await statuses.request();
}
}
} catch (e) {
debugPrint('$e');
} finally {
await requestPermission();
}
}
#override
void initState() {
requestPermission();
super.initState();
}