如果我仅使用提供程序设置一些值以通知侦听器(在 _validateAndSubmit 方法中),则会发生此错误。我想将用户名和图像链接存储在内存中,而不是每次都从 firestore 中获取数据。我正在使用有状态小部件,据我所知,上下文随处可用,并且弹出的对话框工作正常。我真的不明白是什么导致了异常。请帮我解决问题。 enter image description here
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_image_picker/form_builder_image_picker.dart';
import 'package:path/path.dart'
as path; // provides common operations for manipulating paths: joining, splitting, normalizing
import '../providers/user_settings.dart';
class AuthScreen extends StatefulWidget {
@override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
File _pickedImage;
final _initialValues = {
'username': '',
'email': '',
'password': '',
};
var _isLogin = true;
final _formKey = GlobalKey<FormBuilderState>();
final _auth = FirebaseAuth.instance;
var _isLoading = false;
Future<void> _validateAndSubmit() async {
bool valid = _formKey.currentState.validate();
FocusScope.of(context).unfocus(); // close soft keyboard after submiting
if (!valid) {
return;
}
_formKey.currentState.save();
// used below to get user id and to signIn or register user
AuthResult result;
try {
setState(() {
_isLoading = true;
});
if (_isLogin) {
result = await _auth.signInWithEmailAndPassword(
email: _initialValues['email'],
password: _initialValues['password']);
final userId = result.user.uid;
final userDetails =
await Firestore.instance.collection('users').document(userId).get();
Provider.of<UserSettings>(context, listen: false)
.setUserInfo(userDetails['username'], userDetails['image']);
} else {
result = await _auth.createUserWithEmailAndPassword(
email: _initialValues['email'],
password: _initialValues['password']);
final fileName = path.basename(_pickedImage.path);
//print('image: ' + _pickedImage.uri.path);
//final _authResult = await _auth.currentUser();
// we used on complete to make it return future and use await
final ref = FirebaseStorage.instance
.ref()
.child('avatars')
.child(result.user.uid + fileName);
await ref.putFile(_pickedImage).onComplete;
final String imageUrl = await ref.getDownloadURL();
await Firestore.instance
.collection('users')
.document(result.user.uid)
.setData({
'username': _initialValues['username'],
'email': _initialValues['email'],
'image': imageUrl,
});
context
.read<UserSettings>()
.setUserInfo(_initialValues['username'], imageUrl);
//if (this.mounted) {
setState(() {
_isLoading = false;
});
//}
}
} on PlatformException catch (error) {
var msg = 'An Error Occurred, Please Check Your Credentials';
if (error.message != null) {
msg = error.message;
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Error'),
content: Text(msg),
actions: [
RaisedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Ok'),
)
],
));
setState(() {
_isLoading = false;
});
}
} catch (error) {
throw error;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(10),
child: FormBuilder(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (!_isLogin)
FormBuilderTextField(
key: ValueKey('username'),
name: 'username',
keyboardType: TextInputType.name,
decoration: InputDecoration(
labelText: 'Username',
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context,
errorText: 'Please enter a username'),
FormBuilderValidators.minLength(context, 5,
errorText: 'Minimum five characters'),
]),
onSaved: (value) {
_initialValues['username'] = value.trim();
},
onChanged: (value) {},
),
FormBuilderTextField(
key: ValueKey('email'),
name: 'email',
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context,
errorText: 'Please enter an email'),
FormBuilderValidators.email(context,
errorText: 'Please enter a valid email'),
]),
onSaved: (value) {
_initialValues['email'] = value.trim();
},
onChanged: (value) {
//print(value);
},
),
FormBuilderTextField(
key: ValueKey('password'),
name: 'password',
decoration: InputDecoration(
labelText: 'Password',
),
obscureText: true,
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context,
errorText: 'Please enter your password'),
FormBuilderValidators.minLength(context, 8,
errorText: 'Minimum 8 characters'),
]),
onSaved: (value) {
_initialValues['password'] = value.trim();
},
onChanged: (value) {
_initialValues['password'] = value.trim();
},
),
if (!_isLogin)
FormBuilderTextField(
key: ValueKey('repeat'),
name: 'repeat',
decoration: InputDecoration(
labelText: 'Repeat Password',
),
obscureText: true,
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context,
errorText: 'Please repeat your password'),
FormBuilderValidators.minLength(context, 8,
errorText: 'Minimum 8 characters'),
(value) {
if (value != _initialValues['password']) {
return "Not equal";
}
return null;
},
]),
),
SizedBox(
height: 12,
),
if (!_isLogin)
FormBuilderImagePicker(
name: 'image',
//previewWidth: MediaQuery.of(context).size.width * 0.83,
//previewHeight: 220,
maxWidth: 200,
onChanged: (value) {
if (value.isNotEmpty) {
_pickedImage = value[0];
print(_pickedImage);
}
},
onSaved: (value) {
_pickedImage = value[0];
},
//initialValue: _initialValues['image'],
imageQuality: 70,
//valueTransformer: (value) {},
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context,
errorText: 'Please select a photo'),
]),
decoration:
const InputDecoration(labelText: 'Pick Image'),
maxImages: 1,
),
if (_isLoading) CircularProgressIndicator(),
if (!_isLoading)
RaisedButton(
onPressed: _validateAndSubmit,
child: _isLogin ? Text('Login') : Text('SignUp'),
),
if (_isLoading) CircularProgressIndicator(),
if (!_isLoading)
FlatButton(
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
child:
Text(_isLogin ? 'Create a new account' : 'Login'))
],
)),
)),
),
),
);
}
}