I have the following auth provider, and I can sign the user in and the app state changes. But when I do a sign in I notice that nothing is stored in the local storage and when I refresh the page the authStateChanges gives null for the user. I also just tried tho get the current user as a Future which also returns null. What am I doing wrong?
const String oneTimePasswordFunctionName = "requestOneTimePassword";
const String signInWithOneTimePasswordFunctionName = "signInWithOneTimePassword";
class FirebaseAuthProvider extends AuthProvider {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseFunctions _firebaseFunctions = FirebaseFunctions.instance;
Stream<AuthUser> get user {
return _firebaseAuth.authStateChanges().asyncMap((firebaseUser) {
//firebaseUser is always null on refresh
return firebaseUser == null ? AuthUser.empty : firebaseUser.toUser();
});
}
Future<void> requestOneTimePassword({required String email}) async {
final data = {"email": email};
final cloudFunction = _firebaseFunctions.httpsCallable(oneTimePasswordFunctionName);
await cloudFunction.call(data);
}
Future<void> signInWithOneTimePassword({required String email, required String oneTimePassword}) async {
final data = {"email": email, "oneTimePassword": oneTimePassword};
final cloudFunction = _firebaseFunctions.httpsCallable(signInWithOneTimePasswordFunctionName);
final result = await cloudFunction.call(data);
final jwt = result.data["data"]["jwt"] as String;
if (jwt.isEmpty) return;
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
await _firebaseAuth.signInWithCustomToken(jwt);
}
Future<void> signOut() async {
try {
await _firebaseAuth.signOut();
} on Exception {
throw SignOutException();
}
}
}
extension on User {
FutureOr<AuthUser> toUser() async {
final tokenResult = await this.getIdTokenResult(true);
final claims = tokenResult.claims?.map<String, String>((key, value) => MapEntry(key, value.toString()));
return AuthUser(
id: uid,
email: Email.dirty(email ?? ''),
name: displayName ?? '',
photoURL: Uri.parse(photoURL ?? ''),
claims: claims ?? const {},
);
}
}
I really need it to work with the authStateChanges stream, because I want it also to work when the user does a sign out.
I am using the firebase auth emulator. This is my main
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FirebaseAuth.instance.useAuthEmulator("localhost", 9099);
FirebaseFirestore.instance.settings = Settings(
host: "localhost:8080",
sslEnabled: false,
persistenceEnabled: false,
);
FirebaseFunctions.instance.useFunctionsEmulator("localhost", 5001);
Future<dynamic> Function() initializeFirebase = () async {
if (Firebase.apps.length == 0) await Firebase.initializeApp();
};
await Future.wait([
initializeFirebase(),
EasyLocalization.ensureInitialized(),
]);
runApp(_buildAppWithDependencies());
}
I am testing in the latest version of google chrome
Versions
flutter: 2.5.3 (stable)
firebase_core: ^1.10.0
firebase_auth: ^3.2.0
Related
I have some mistakes with flutter and firebase, if someone can help would be great here is my auth controller
class AuthController extends GetxController {
final FirebaseAuth auth = FirebaseAuth.instance;
final Rxn<User> _firebaseUser = Rxn<User>();
Rx<XFile>? _pickedImage;
XFile? get profilePhoto => _pickedImage?.value;
// final user = FirebaseAuth.instance.currentUser.obs;
Rxn<User> get user => _firebaseUser;
// final user = FirebaseAuth.instance.currentUser;
#override
onInit() {
_firebaseUser.bindStream(auth.authStateChanges());
super.onInit();
}
// void register(
// String name, String email, String password, XFile? image) async {
// try {
// UserCredential _authResult = await auth.createUserWithEmailAndPassword(
// email: email.trim(), password: password);
// //create user in database.dart
// String downloadUrl = await uploadToStorage(image!);
// UserModel _user = UserModel(
// id: _authResult.user?.uid,
// name: name,
// email: _authResult.user?.email,
// profilePic: downloadUrl,
// );
// if (await Database().createNewUser(_user)) {
// Get.find<UserController>().user = _user;
// }
// } catch (e) {
// Get.snackbar(
// "Error creating Account",
// e.toString(),
// snackPosition: SnackPosition.BOTTOM,
// );
// }
// }
void register(
String name, String email, String password, XFile? image) async {
try {
if (name.isNotEmpty &&
email.isNotEmpty &&
password.isNotEmpty &&
image != null) {
// save out user to our ath and firebase firestore
UserCredential _authResult = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
String downloadUrl = await uploadToStorage(image);
UserModel _user = UserModel(
id: _authResult.user?.uid,
name: name,
email: _authResult.user?.email,
profilePic: downloadUrl,
);
if (await Database().createNewUser(_user)) {
Get.find<UserController>().user = _user;
} else {
Get.snackbar(
'Error Creating Account',
'Please enter all the fields',
);
}
}
} catch (e) {
Get.snackbar(
'Error Creating Account',
e.toString(),
);
}
}
void login(String email, password) async {
try {
UserCredential _authResult = await auth.signInWithEmailAndPassword(
email: email.trim(), password: password);
Get.find<UserController>().user =
await Database().getUser(_authResult.user?.uid ?? '');
} catch (e) {
Get.snackbar("About User", "User message",
snackPosition: SnackPosition.BOTTOM,
titleText: Text("Acount creation failed"),
messageText:
Text(e.toString(), style: TextStyle(color: Colors.white)));
}
}
Future<void> signOut() async {
await auth.signOut();
Get.find<UserController>().clear();
}
Future pickImage() async {
print("call on click add photo icon");
final ImagePicker _picker = ImagePicker();
final XFile? pickedImage =
await _picker.pickImage(source: ImageSource.gallery);
print('picked image filled with image from gallery'); //This doesnt print at
if (pickedImage != null) {
Get.snackbar('Profile Picture',
'You have successfully selected your profile picture!');
// print(pickedImage.path);
}
_pickedImage = Rx<XFile>(pickedImage!);
// print(_pickedImage);
// print(profilePhoto);
}
// upload to firebase storage
Future<String> uploadToStorage(XFile? image) async {
Reference ref = FirebaseStorage.instance
.ref('')
.child('profilePics')
.child(auth.currentUser!.uid);
// print(ref);
UploadTask uploadTask = ref.putFile(File(image?.path ?? 'idemo'));
print(uploadTask);
// TaskSnapshot snap = await uploadTask;
String downloadUrl = await (await uploadTask).ref.getDownloadURL();
print(downloadUrl);
return downloadUrl;
}
}
Here is my function to createNewUser
class Database {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<bool> createNewUser(UserModel user) async {
try {
await _firestore.collection("users").doc(user.id).set({
"name": user.name,
"email": user.email,
"profilePhoto": user.profilePic
});
return true;
} catch (e) {
print(e);
return false;
}
}
Here is HomeController
class HomeController extends GetxController {
final Rxn<List<TodoModel>> todoList = Rxn<List<TodoModel>>([]);
var selectedDate = DateTime.now().obs;
List<TodoModel>? get todos => todoList.value;
#override
void onInit() {
super.onInit();
String? uid = Get.find<AuthController>().auth.currentUser?.uid ?? '';
print(uid);
todoList.bindStream(Database().todoStream(uid));
}
chooseDate() async {
DateTime? pickedDate = await showDatePicker(
context: Get.context!,
initialDate: selectedDate.value,
firstDate: DateTime(2000),
lastDate: DateTime(2024),
//initialEntryMode: DatePickerEntryMode.input,
// initialDatePickerMode: DatePickerMode.year,
);
if (pickedDate != null && pickedDate != selectedDate.value) {
selectedDate.value = pickedDate;
}
}
}
and here is View page
GetX<HomeController>(
init: Get.put<HomeController>(HomeController()),
builder: (HomeController todoController) {
if (todoController.todos != null) {
// print(todoController.todos?.done ?? false);
return Expanded(
child: ListView.builder(
itemCount: todoController.todos?.length,
itemBuilder: (_, index) {
return TodoCard(
uid: controller.user.value?.uid ?? '',
todo: todoController.todos![index],
);
},
),
);
} else {
return Text("loading...");
}
},
),
So, I have an error when I register a new user I got this error:
The following assertion was thrown building Builder(dirty):
a document path must be a non-empty string
Failed assertion: line 116 pos 14: ‘path.isNotEmpty’
And here is output from terminal:
The relevant error-causing widget was
GetMaterialApp
lib/main.dart:23
When the exception was thrown, this was the stack
#2 _JsonCollectionReference.doc
#3 Database.todoStream
#4 HomeController.onInit
#5 GetLifeCycleBase._onStart
#6 InternalFinalCallback.call
#7 GetInstance._startController
#8 GetInstance._initDependencies
#9 GetInstance.find
#10 GetInstance.put
#11 Inst.put
So a problem is with this path, and when I reload from the visual studio I god the right user with the right data. So the problem is when I register a user for the first time.
It looks like uid is empty, which you should also be able to see from looking up print(uid); in your output.
When your application or web page loads, Firebase automatically tries to restore the previously signed in user from its local state. This requires that it makes a call to the server however (for example to check if the account has been disabled) and while that call is going on, your main code continues to execute and the currentUser variable is going to be null.
Your code needs to take this into account. The easiest way to do this is to not depend on currentUser, but instead to use an reactively respond to changes in the authentication state as shown in the first example in the documentation on getting the current user:
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user != null) {
print(user.uid);
}
});
The authStateChange method here returns a stream that fires an event whenever the authentication state changes, so when the user signs in or signs out. The common way to use this stream is to either set the user to the state of your widget, or to use the stream directly in a StreamBuilder.
I'm trying to update my documents in firestore, so when I'm trying to update it keeps updating without stopping. The first time it updates using the data from the signup dart file, then the second time it updates using the data from another dart file.
Here is the code for the signup:
FirebaseAuth auth = FirebaseAuth.instance;
await auth.createUserWithEmailAndPassword(
email: emailController.text, password: passwordController.text)
.then((value) => {
Navigator.pushNamed(context, 'DialogFlow'),
user=auth.currentUser,
user.sendEmailVerification(),
DatabaseService(uid:user.uid).UpdateUserData("", emailController.text, ChatScreenState().mess)
Here is the code for the other dart file:
#override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToEnd());
FirebaseAuth auth = FirebaseAuth.instance;
user=auth.currentUser;
DatabaseService db = DatabaseService(uid: user.uid);
return StreamBuilder(
stream: FirebaseFirestore.instance.collection("users").doc(user.uid).snapshots(),
builder: (context , snapshot){
print("====================================");
print(snapshot.data);
print("====================================");
if (snapshot.data != null) {
this.userTestMessage = "";
shhh = pressed ? true : false;
flag = true;
print(Retrieved_messages);
if (Retrieved_messages==false) {
this.messsages = snapshot.data['messsages'];
Retrieved_messages=true;
}
db.UpdateUserData(
user.displayName, user.email, this.messsages);
print(mess);
print(Retrieved_messages);
print("==============================");
print(snapshot.data);
print("==============================");
}
if (db.getUserMessages() == null) {
if (user != null) {
db.UpdateUserData(
user.displayName, user.email, this.messsages);
}
}
And the code for the database which sets and updates the documents is:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:satoshi/models/Userdata.dart';
import 'package:satoshi/widgets/dialog_flow.dart';
class DatabaseService {
//collection reference
final String uid;
List messsages=[];
DatabaseService({this.uid, this.messsages});
final CollectionReference userCollection = FirebaseFirestore.instance
.collection('users');
SetUserData(String Username, String Email,
List messsages) async
{ try {
return await FirebaseFirestore.instance.collection("users").doc(uid).set({
'Username': Username,
'Email': Email,
'messsages': messsages,
}
);
}catch(e){
print(e+" this is the error");
}
}
UpdateUserData(String Username, String Email,
List messsages) async
{ try {
return await FirebaseFirestore.instance.collection("users").doc(uid).update({
'Username': Username,
'Email': Email,
'messsages': messsages,
}
);
}catch(e){
print(e+" this is the error");
}
}
Future getUserMessages() async
{
DocumentSnapshot UserDetail = await userCollection.doc(uid).get();
var msg = UserDetail.data()['messsages'];
return await msg;
}
Stream<QuerySnapshot> get users {
return userCollection.snapshots();
}
Userdata userDataFromSnapshot(DocumentSnapshot snapshot) {
return Userdata(uid: uid,
name: snapshot.get('Username'),
email: snapshot.get('Email'),
messsages: snapshot.get('messsages'),
);
}
Stream<Userdata> get userData {
return userCollection.doc(uid).snapshots().asyncMap(userDataFromSnapshot);
}
}
Note: it keeps adding the data in the signup code, then adds the data in the other dart file, which results in an endless loop, also the snapshot isn't updating, it remains the same data as the signup
You are calling the Update function inside the stream builder so what it basically does is once the update function is called firebase gets notified of the document change and rebuilds the widget so again the update function is called and it turns into an infinite loop. what you can do is add any condition such that it won't get called again once the data is updated.
Example
if (<Somecondition>){
db.UpdateUserData(
user.displayName, user.email, this.messsages);
}
I am trying to set up with apple sign in with the following code. When tapping the button nothing happens.
I get the following error:
Tried calling: authorizationCode
flutter: NoSuchMethodError: The getter 'authorizationCode' was called on null.
Receiver: null
How would I fix this?
Future<bool> get appleSignInAvailable => AppleSignIn.isAvailable();
Future<User> appleSignIn() async {
try {
final AuthorizationResult appleResult =
await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
if (appleResult.error != null) {
// handle errors from Apple
}
final AuthCredential credential =
OAuthProvider('apple.com').credential(
accessToken:
String.fromCharCodes(appleResult.credential.authorizationCode),
idToken: String.fromCharCodes(appleResult.credential.identityToken),
);
UserCredential result =
await Global.fbAuth.signInWithCredential(credential);
User user = result.user;
updateUserData(user);
return user;
} catch (error) {
print(error);
return null;
}
}
If you are using iOS 14 simulator, this may be due to the issue reported here. The workaround would be to use a real device for debugging or use the iOS 13 simulator
Also, see this thread for reference
I have faced same kind of issue in one of my projects.You have to add your sha key in firebase and facebook to resolve the issue.
Also you can try the below code,
import 'package:apple_sign_in/apple_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/services.dart';
class AuthService {
final _firebaseAuth = FirebaseAuth.instance;
Future<User> signInWithApple({List<Scope> scopes = const []}) async {
// 1. perform the sign-in request
final result = await AppleSignIn.performRequests(
[AppleIdRequest(requestedScopes: scopes)]);
// 2. check the result
switch (result.status) {
case AuthorizationStatus.authorized:
final appleIdCredential = result.credential;
final oAuthProvider = OAuthProvider('apple.com');
final credential = oAuthProvider.credential(
idToken: String.fromCharCodes(appleIdCredential.identityToken),
accessToken:
String.fromCharCodes(appleIdCredential.authorizationCode),
);
final authResult = await _firebaseAuth.signInWithCredential(credential);
final firebaseUser = authResult.user;
if (scopes.contains(Scope.fullName)) {
final displayName =
'${appleIdCredential.fullName.givenName} ${appleIdCredential.fullName.familyName}';
await firebaseUser.updateProfile(displayName: displayName);
}
return firebaseUser;
case AuthorizationStatus.error:
throw PlatformException(
code: 'ERROR_AUTHORIZATION_DENIED',
message: result.error.toString(),
);
case AuthorizationStatus.cancelled:
throw PlatformException(
code: 'ERROR_ABORTED_BY_USER',
message: 'Sign in aborted by user',
);
default:
throw UnimplementedError();
}
}
}
This question already has answers here:
Undefined class 'FirebaseUser'
(6 answers)
Closed 2 years ago.
I am in the process of migrating this code to the latest version of firebase and the only part I am struggling with at the moment is this code from my auth.dart file.
#override
Stream<Users> get onAuthStateChanges {
return _firebaseAuth.onAuthStateChanges.map(_userFromFirebase);
}
To migrate to the latest version, I wrote it this way:
#override
Stream<Users> get authStateChanges {
return _firebaseAuth.authStateChanges.map(_userFromFirebase);
}
I keep getting this error:
The method 'map' isn't defined for the type 'Function'.
I can't seem to find any documentation on how to write it properly. Would someone happen to know how to fix this?
Thanks in advance for your help
PS
In case you're wondering why I'm migrating this code, my Emulator keeps complaining that the Firebase Core plugin is missing (I guess due to the Google-services.json file) and none of the authentication buttons work. Upon clicking I get this "return firebase.google.cms" error". The Simulator was working fine until I did a recent update on Xcode and now it's giving me this weird error code and will not complete the flutter run. So I figured if I get the latest version of firebase and update the code, accordingly, I can use my Simulator and/or Emulator again. Then I encountered the above problem with the authStateChanges.map code and here we are.
Here is my auth.dart file in its entirety for your reference:
class Users {
final String uid;
Users({#required this.uid});
}
abstract class AuthBase {
Stream<Users> get authStateChanges;
Future<Users> currentUser();
Future<Users> signInAnonymously();
Future<Users> signInWithEmailAndPassword(String email, String password);
Future<Users> createUserWithEmailAndPassword(String email, String password);
Future<Users> signInWithGoogle();
Future<void> signOut();
}
class Auth implements AuthBase {
final _firebaseAuth = FirebaseAuth.instance;
//To avoid confusion due to updates, "Users" come from the class Users and "User" replaces the deprecated "FirebaseUser".
Users _userFromFirebase(User user) {
if (user == null) {
return null;
}
return Users(uid: user.uid);
}
#override
Stream<Users> get authStateChanges {
return _firebaseAuth.authStateChanges.map(_userFromFirebase);
}
#override
Future<Users> currentUser() async {
final user = _firebaseAuth.currentUser;
return _userFromFirebase(user);
}
#override
Future<Users> signInAnonymously() async {
final authResult = await _firebaseAuth.signInAnonymously();
return _userFromFirebase(authResult.user);
}
#override
Future<Users> signInWithEmailAndPassword(String email, String password) async {
final authResult = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
return _userFromFirebase(authResult.user);
}
#override
Future<Users> createUserWithEmailAndPassword(
String email, String password) async {
final authResult = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
return _userFromFirebase(authResult.user);
}
#override
Future<Users> signInWithGoogle() async {
final googleSignIn = GoogleSignIn();
final googleAccount = await googleSignIn.signIn();
if (googleAccount != null) {
final googleAuth = await googleAccount.authentication;
if (googleAuth.accessToken != null && googleAuth.idToken != null) {
final authResult = await _firebaseAuth.signInWithCredential(
GoogleAuthProvider.credential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken),
);
return _userFromFirebase(authResult.user);
} else {
throw PlatformException(
code: 'ERROR_MISSING_GOOGLE_AUTH_TOKEN',
message: 'Missing Google Auth Token');
}
} else {
throw PlatformException(
code: 'ERROR_ABORTED_BY_USER', message: 'Sign in aborted by user');
}
}
#override
Future<void> signOut() async {
final googleSignin = GoogleSignIn();
await googleSignin.signOut();
await _firebaseAuth.signOut();
}
}
Here are the dependencies I'm using:
dependencies:
flutter:
sdk: flutter
font_awesome_flutter: ^8.8.1
image_picker: ^0.6.7+6
provider: ^4.3.2+1
path_provider: ^1.6.14
path: ^1.7.0
firebase_core: ^0.5.0
cloud_firestore: ^0.14.1+2
google_sign_in: ^4.5.3
firebase_auth: ^0.18.1+1
firebase_storage: ^4.0.1
image: ^2.1.18
animator: ^2.0.1
geolocator: ^5.3.2+2
uuid: ^2.2.2
cached_network_image: ^2.3.2+1
bubble: ^1.1.9+1
flutter_cupertino_date_picker: ^1.0.26+2
In the new library version, authStateChanges is a method, so you need to put () after it.
return _firebaseAuth.authStateChanges().map(_userFromFirebase);
I was following a tutorial to create an authentication system in flutter using firebase. Registration works as intended and the user is posted to my firebase database, however, when I try to login with the correct credentials, I get:
I/flutter (26424): user A a#a.com added
I/InputMethodManager(26424): showSoftInput
I/InputMethodManager(26424): mServedView =com.waifuhub.app;view =com.waifuhub.app;flags =0
I/HwSecImmHelper(26424): mSecurityInputMethodService is null
W/InputMethodManager(26424): startInputReason = 3
W/IInputConnectionWrapper(26424): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(26424): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(26424): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper(26424): requestCursorAnchorInfo on inactive InputConnection
I/InputMethodManager(26424): showSoftInput
I/InputMethodManager(26424): mServedView =com.waifuhub.app;view =com.waifuhub.app;flags =0
I/HwSecImmHelper(26424): mSecurityInputMethodService is null
W/InputMethodManager(26424): startInputReason = 3
V/AudioManager(26424): playSoundEffect effectType: 0
V/AudioManager(26424): querySoundEffectsEnabled...
I/HwSecImmHelper(26424): mSecurityInputMethodService is null
I/ViewRootImpl(26424): jank_removeInvalidNode all the node in jank list is out of time
I/flutter (26424): Sign In Error: NoSuchMethodError: The getter 'data' was called on null.
I/flutter (26424): Receiver: null
I/flutter (26424): Tried calling: data
Application finished.
Exited (sigterm)
The code responsible for signing in is as follows:
void _emailLogin(
{String email, String password, BuildContext context}) async {
if (_formKey.currentState.validate()) {
try {
SystemChannels.textInput.invokeMethod('TextInput.hide');
await _changeLoadingVisible();
//need await so it has chance to go through error if found.
await StateWidget.of(context).logInUser(email, password);
await Navigator.pushNamed(context, '/');
} catch (e) {
_changeLoadingVisible();
print("Sign In Error: $e");
String exception = Auth.getExceptionText(e);
Flushbar(
title: "Sign In Error",
message: exception,
duration: Duration(seconds: 5),
)..show(context);
}
} else {
setState(() => _autoValidate = true);
}
}
class StateWidget extends StatefulWidget {
final StateModel state;
final Widget child;
StateWidget({
#required this.child,
this.state,
});
// Returns data of the nearest widget _StateDataWidget
// in the widget tree.
static _StateWidgetState of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<_StateDataWidget>().data;
}
#override
_StateWidgetState createState() => new _StateWidgetState();
}
class _StateWidgetState extends State<StateWidget> {
StateModel state;
//GoogleSignInAccount googleAccount;
//final GoogleSignIn googleSignIn = new GoogleSignIn();
#override
void initState() {
super.initState();
if (widget.state != null) {
state = widget.state;
} else {
state = new StateModel(isLoading: true);
initUser();
}
}
Future<Null> initUser() async {
//print('...initUser...');
FirebaseUser firebaseUserAuth = await Auth.getCurrentFirebaseUser();
User user = await Auth.getUserLocal();
Settings settings = await Auth.getSettingsLocal();
setState(() {
state.isLoading = false;
state.firebaseUserAuth = firebaseUserAuth;
state.user = user;
state.settings = settings;
});
}
Future<void> logOutUser() async {
await Auth.signOut();
FirebaseUser firebaseUserAuth = await Auth.getCurrentFirebaseUser();
setState(() {
state.user = null;
state.settings = null;
state.firebaseUserAuth = firebaseUserAuth;
});
}
Future<void> logInUser(email, password) async {
String userId = await Auth.signIn(email, password);
User user = await Auth.getUserFirestore(userId);
await Auth.storeUserLocal(user);
Settings settings = await Auth.getSettingsFirestore(userId);
await Auth.storeSettingsLocal(settings);
await initUser();
}
#override
Widget build(BuildContext context) {
return new _StateDataWidget(
data: this,
child: widget.child,
);
}
}
class _StateDataWidget extends InheritedWidget {
final _StateWidgetState data;
_StateDataWidget({
Key key,
#required Widget child,
#required this.data,
}) : super(key: key, child: child);
// Rebuild the widgets that inherit from this widget
// on every rebuild of _StateDataWidget:
#override
bool updateShouldNotify(_StateDataWidget old) => true;
}
static Future<String> signIn(String email, String password) async {
FirebaseUser user = (await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password))
.user;
return user.uid;
}
class Validator {
static String validateEmail(String value) {
Pattern pattern = r'^[a-zA-Z0-9.]+#[a-zA-Z0-9]+\.[a-zA-Z]+';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Please enter a valid email address.';
else
return null;
}
static String validatePassword(String value) {
Pattern pattern = r'^.{6,}$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Password must be at least 6 characters.';
else
return null;
}
static String validateName(String value) {
Pattern pattern = r"^[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)*$";
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Please enter a name.';
else
return null;
}
static String validateNumber(String value) {
Pattern pattern = r'^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value))
return 'Please enter a number.';
else
return null;
}
}
And my dependencies in pubsec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_launcher_icons: ^0.7.2
cupertino_icons: ^0.1.2
firebase_auth: ^0.15.5+3
cloud_firestore: ^0.13.4+2
flushbar: 1.9.1
shared_preferences: ^0.5.6+3
dev_dependencies:
flutter_test:
sdk: flutter
Upon further debugging, I think the error is due to the fact that null context is being passed to
_StateWidgetState, however, I am not sure if this is so, or how to solve this. Any help would be highly appreciated!
Not sure, but it seems you're missing calling
_formKey.currentState.save();
after calling _formKey.currentState.validate().
Otherwise this line is causing the error:
static _StateWidgetState of(BuildContext context) {
return (context.dependOnInheritedWidgetOfExactType() as _StateDataWidget)
.data;
}
This (context.dependOnInheritedWidgetOfExactType() as _StateDataWidget) is returning null
change it to:
return (context.inheritFromWidgetOfExactType(_StateDataWidget) as _StateDataWidget).data;
or
return context.dependOnInheritedWidgetOfExactType<_StateDataWidget>().data;