firebase auth with flutter - flutter

Please I need help I can't connect firebase with flutter I have this problem I have this message:
Firebase: Could not find the Android Application module. Only Android Application Modules can be connected to Firebase online projects. Create a new Android Application Module or create/import a different Android Studio project.
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'homepage.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
String _email;
String _password;
GlobalKey<FormState> _keyform = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: new Text("flutter login"),
),
body: new Form(
key: _keyform,
child: new Column(
children: <Widget>[
new TextFormField(
validator: (input) {
if (input.isEmpty) {
return "saisir votre email";
}
},
onSaved: (input) => _email = input,
decoration: InputDecoration(labelText: "email"),
),
new TextFormField(
validator: (input) {
if (input.length < 6) {
return "changer votre mot de passe";
}
},
onSaved: (input) => _password = input,
obscureText: true,
decoration: InputDecoration(labelText: "mot de passe"),
),
RaisedButton(
onPressed: signin,
child: Text("envoyer"),
)
],
)),
);
}
Future<void> signin() async {
final formState = _keyform.currentState;
if (formState.validate()) {
formState.save();
try {
FirebaseUser user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return new homepage();
}));
} catch (e) {
print(e.message);
}
;
}
}
}

Related

Cannot access from Sign In with email and password using Navigator.push() to other window in Flutter [duplicate]

This question already has answers here:
No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() in Flutter and Firebase
(27 answers)
Closed 2 years ago.
I want to access from Sign In to Home window, but when I try to sign in with existing account the button doesn't work and the window stays the same.
import 'package:finalproject/Pages/home.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => new _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String _email, _password;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: Text('Sign in'),
),
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
validator: (input) {
if (input.isEmpty) {
return ' Write your email';
}
return null;
},
onSaved: (input) => _email = input,
decoration: InputDecoration(labelText: ' Email'),
),
TextFormField(
validator: (input) {
if (input.length < 6) {
return ' Write your password';
}
return null;
},
onSaved: (input) => _password = input,
decoration: InputDecoration(labelText: ' Password'),
obscureText: true,
),
RaisedButton(
onPressed: signIn,
child: Text('Sign in'),
),],),),);}
void signIn() async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
try {
// ignore: deprecated_member_use
UserCredential authResult = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
final User user = authResult.user;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Home()),
);
} catch (e) {
print(e.message);
}}}}
Also, I always get this message after I press the Sign in button.
I/flutter ( 3130): No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
Maybe this could be the reason of it?
You need to initialize the FirebaseApp. You can do it in your main function like this:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}

The argument type 'Context' can't be assigned to the parameter type 'BuildContext'

I AM trying to create a login page with flutter and firebase the navigator worked properly in all files but when coming to this page it shows an error at the context in the navigator
the error is
'The argument type 'Context' can't be assigned to the parameter type 'BuildContext'.
the following are the details of my flutter version:
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
curved_navigation_bar: ^0.3.2
oktoast:
firebase_auth: ^0.5.20
please help me to solve this
import 'package:path/path.dart';
import 'package:codej/effects.dart';
import 'package:flutter/material.dart';
import 'package:oktoast/oktoast.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Auth extends StatefulWidget {
#override
_AuthState createState() => new _AuthState();
}
class _AuthState extends State<Auth>{
String _email, _password;
final GlobalKey<FormState> formkey = GlobalKey<FormState>();
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(appBar: AppBar(
title: Text("Authentication"),
),
// TODO: implement build
body: Form(
key: formkey,
child: Column(
children: <Widget>[
TextFormField(
validator: (input){
if(input.isEmpty){
showToastWidget(Text("please enter your user name"));
}
},
onSaved: (input) => _email = input,
decoration: InputDecoration(
labelText: 'Email'
),
),
TextFormField(
validator: (input){
if(input.length < 6){
showToastWidget(Text("please enter your password atleast 6 characters"));
}
},
onSaved: (input) => _password = input,
decoration: InputDecoration(
labelText: 'Password'
),
obscureText: true,
),
RaisedButton(onPressed: (){
},
child: Text("Sign in"),)
],
)),
);
}
void signinAuth() async{
final formState = formkey.currentState;
if(formState.validate()){
formState.save();
try{
FirebaseUser user = await FirebaseAuth.instance.signInWithEmailAndPassword(email: _email, password: _password);
Navigator.push(context, MaterialPageRoute(builder: (context) => BottomNav())); //BottomNav loacted in other file
}catch(e){
print(e.message);
}
}
}
}
This is working on my pc, so it is version problem. Try updating your flutter and dart sdk, if this is not the solution for you, just pass BuildContext to your signinAuth like this
void signinAuth(BuildContext context) async {
final formState = formkey.currentState;
if (formState.validate()) {
formState.save();
try {
FirebaseUser user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
BottomNav())); //BottomNav loacted in other file
} catch (e) {
print(e.message);
}
}
}

Submitting form works on iOS and web, but not on Android

Very simple login form, works on iOS and web, but not on Android. Is there something fundamental, or is there some bug related to this. Basically, clicking on the "submit" button does not make make the login call.
The AppState is a singelton class in case you want to know.
Basically it is identical to the form defined in the Flutter documentation: https://flutter.dev/docs/cookbook/forms/validation
import 'package:flutter/material.dart';
import 'package:flutter_poc/app_state.dart';
import 'package:http/http.dart' as http;
import 'dart:convert' as convert;
class AuthPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(child: MyCustomForm()),
),
);
}
}
class MyCustomForm extends StatefulWidget {
#override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
class MyCustomFormState extends State<MyCustomForm> {
final _formKey = GlobalKey<FormState>();
String _username;
String _password;
Future<String> getAuthToken(username, password) async {
final postData = {'username': username, 'password': password};
final loginUrl = 'https://xxx/login';
final response = await http.post(loginUrl, body: postData);
if (response.statusCode == 200) {
final data = convert.jsonDecode(response.body);
return data['token'];
}
return null;
}
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: InputDecoration(hintText: 'Email'),
validator: (value) {
if (value.isEmpty) {
return 'Enter email';
}
return null;
},
onSaved: (val) => {_username = val},
),
TextFormField(
decoration: InputDecoration(hintText: 'Password'),
validator: (value) {
if (value.isEmpty) {
return 'Enter password';
}
return null;
},
obscureText: true,
onSaved: (val) => {_password = val},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
onPressed: () async {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
final token = await getAuthToken(_username, _password);
if (token == null) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('failed to login')));
} else {
AppState().setToken(token);
}
}
},
child: Text('Submit'),
),
),
],
),
);
}
}
I didn't notice the problem directly, as I never got any direct response, so always rebooted. But now when I ran in verbose mode I took a cup of coffee, and noticed that there were a DNS resolution error. Basically the Android emulator that I used did not pick up the DNS from the host machine, so it could not resolve the api address. Solved my problem by setting dns manually, like here: Internet stopped working on Android Emulator (Mac OS)

Manually setting Flutter Validation Error

After validating a form and sending a request from flutter to the server backend: I want to set any potential error message from the server to be displayed in the original form. Preferably exactly like a validation error.
For instance:
Widget build(BuildContext context) {
...
TextFormField(
onFieldSubmitted: (value) => _signIn(),
validator: (input) {
if (input.length < 6)
return 'Your password is too short';
return null;
},
onSaved: (input) => _password = input,
decoration: InputDecoration(
labelText: 'Password',
),
obscureText: true,
)
...
}
Future<void> _signIn() async {
final formState = _formKey.currentState;
if (!formState.validate()) return;
formState.save();
try {
... // do fancy request stuff
} catch (e) {
// this is where I want to set the "validation" error
}
}
It's actually super simple and the validation error still works aswell.
String? _errorMsg;
Widget build(BuildContext context) {
...
TextFormField(
onFieldSubmitted: (value) => _signIn(),
validator: (input) {
if (input.length < 6)
// will set the errorText directly, no need for a variable here
return 'Your password is too short';
return null;
},
onSaved: (input) => _password = input,
decoration: InputDecoration(
labelText: 'Password',
errorText: _errorMsg,
),
obscureText: true,
)
...
}
Future<void> _signIn() async {
setState(() {
_errorMsg = null; // clear any existing errors
});
final formState = _formKey.currentState;
if (!formState.validate()) return;
formState.save();
try {
... // do fancy request stuff
} catch (e) {
setState(() {
_errorMsg = 'Wrong password.';
});
}
}
I suppose, I could think of a solution, but I think it's kind of ugly.
I could have an "error" variable, that is set when the request fails.
I would then call formState.validate() a second time, in there: check the error variable and return it if it's not null.
You can use flutter_form_bloc and use addError method of TextFieldBloc.
usernameField.addError('That username is taken. Try another.');
Keep in mind that you can also use asynchronous validators.
This is a complete example:
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^0.21.0
form_bloc: ^0.5.0
flutter_form_bloc: ^0.4.1+1
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:form_bloc/form_bloc.dart';
void main() {
runApp(MaterialApp(home: SignUpForm()));
}
class SignUpFormBloc extends FormBloc<String, String> {
final usernameField = TextFieldBloc();
final passwordField =
TextFieldBloc(validators: [Validators.passwordMin6Chars]);
#override
List<FieldBloc> get fieldBlocs => [usernameField, passwordField];
#override
Stream<FormBlocState<String, String>> onSubmitting() async* {
// Form logic...
try {
await _signUp(
throwException: true,
username: usernameField.value,
password: passwordField.value,
);
yield currentState.toSuccess();
} catch (e) {
// When get the error from the backend you can
// add the error to the field:
usernameField.addError('That username is taken. Try another.');
yield currentState
.toFailure('The error was added to the username field.');
}
}
Future<void> _signUp({
#required bool throwException,
#required String username,
#required String password,
}) async {
print(username);
print(password);
await Future<void>.delayed(Duration(seconds: 2));
if (throwException) throw Exception();
}
}
class SignUpForm extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider<SignUpFormBloc>(
builder: (context) => SignUpFormBloc(),
child: Builder(
builder: (context) {
final formBloc = BlocProvider.of<SignUpFormBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Sign Up Form')),
body: FormBlocListener<SignUpFormBloc, String, String>(
onSubmitting: (context, state) {
// Show the progress dialog
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => WillPopScope(
onWillPop: () async => false,
child: Center(
child: Card(
child: Container(
width: 80,
height: 80,
padding: EdgeInsets.all(12.0),
child: CircularProgressIndicator(),
),
),
),
),
);
},
onSuccess: (context, state) {
// Hide the progress dialog
Navigator.of(context).pop();
// Navigate to success screen
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => SuccessScreen()));
},
onFailure: (context, state) {
// Hide the progress dialog
Navigator.of(context).pop();
// Show snackbar with the error
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(state.failureResponse),
backgroundColor: Colors.red[300],
),
);
},
child: ListView(
children: <Widget>[
TextFieldBlocBuilder(
textFieldBloc: formBloc.usernameField,
decoration: InputDecoration(labelText: 'Username'),
),
TextFieldBlocBuilder(
textFieldBloc: formBloc.passwordField,
decoration: InputDecoration(labelText: 'Password'),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: formBloc.submit,
child: Center(child: Text('SUBMIT')),
),
),
],
),
),
);
},
),
);
}
}
class SuccessScreen extends StatelessWidget {
const SuccessScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[300],
body: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Icon(
Icons.sentiment_satisfied,
size: 100,
),
RaisedButton(
color: Colors.green[100],
child: Text('Sign out'),
onPressed: () => Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => SignUpForm())),
)
],
),
),
),
);
}
}
A simple solution:
Make a key for the widgets state:
GlobalKey<_CustomErrorTextField> _passwordTextFieldState = GlobalKey();
Set the Error message using the key:
_passwordTextFieldState.currentState.updateError(errorMsg);
Reset the error after 2 seconds:
Future.delayed(Duration(seconds: 2), () {
// Runs after duration sec
_passwordTextFieldState.currentState.updateError(null);
});
Set up the widget (be sure to set the key):
CustomErrorTextField(
key: _passwordTextFieldState,
label: "Password",
currentPassword: password,
validator: yourValidator,
callback: passwordCallback,
obscureText: hidePassword.value - a bool value show/hide password
)
Here is the Widget:
class CustomErrorTextField extends StatefulWidget {
CustomErrorTextField({
Key key,
this.label,
this.currentPassword,
this.validator,
this.callback,
this.obscureText = false
}): super(key: key);
final String label;
final String currentPassword;
final FormFieldValidator<String> validator;
final Function callback;
final obscureText;
#override
_CustomErrorTextField createState() => _CustomErrorTextField();
}
class _CustomErrorTextField extends State<CustomErrorTextField> {
String errorMsg;
updateError(String errorMsg){
setState(() {
this.errorMsg = errorMsg;
});
}
#override
Widget build(BuildContext context) {
return TextFormField(
decoration: InputDecoration(
labelText: widget.label,
errorText: errorMsg
),
initialValue: widget.currentPassword,
keyboardType: TextInputType.visiblePassword,
validator: widget.validator,
onSaved: (String val) {
widget.callback(val);
},
obscureText: widget.obscureText,
);
}
}

Flutter: objects inside InheritedWidget cannot change value

I have a question about InheritedWidget. Since most of the pages in my apps used the user object, so I created an InheritedWidget class called UserProvider so I don't need to pass the user object along my widget tree. It works fine until I tried to logout and login with another user. The User remains the old one. I do a bit of research and it seems that the value inside InheritedWidget class cannot be changed. It there a way to rewrite it so I can take advantage of InheritedWidget and still able to change the value of the user object?
UserProvider Class:
class UserProvider extends InheritedWidget {
UserProvider({Key key, Widget child, this.user}) : super(key: key, child: child);
final User user;
/* #override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
*/
#override
bool updateShouldNotify(UserProvider oldWidget) {
return user != oldWidget.user;
}
static UserProvider of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(UserProvider) as UserProvider);
}
}
HomePage class:
class HomePage extends StatefulWidget {
HomePage({this.auth, this.onSignedOut,this.userId});
final BaseAuth auth;
final VoidCallback onSignedOut;
final String userId;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String _userName;
String _userEmail;
String _userPicURL;
User currentUser;
void _signOut() async {
try {
await widget.auth.signOut();
widget.onSignedOut();
} catch (e) {
print(e);
}
}
#override
void initState() {
super.initState();
currentUser = User(widget.userId);
currentUser.loadUserData();
...
#override
Widget build(BuildContext context) {
return UserProvider(
user: currentUser,
...
LoginPage class:
class LoginPage extends StatefulWidget {
LoginPage({this.auth, this.onSignedIn});
final BaseAuth auth;
final VoidCallback onSignedIn;
#override
//_LoginPageState createState() => _LoginPageState();
State<StatefulWidget> createState() => _LoginPageState();
}
enum FormType {
login,
register
}
class _LoginPageState extends State<LoginPage> {
final formKey = new GlobalKey<FormState>();
String _uid;
String _email;
String _password;
String _birthday;
String _fullname;
FormType _formType = FormType.login;
bool validateAndSave() {
final form = formKey.currentState;
if (form.validate()) {
form.save();
return true;
} else {
return false;
}
}
void _addData(String email, String fullname, String birthday) async {
_uid = await widget.auth.currentUser();
Firestore.instance.runTransaction((Transaction transaction) async{
Firestore.instance.collection("Users").document(_uid).setData(
{
"id": _uid,
"email" : email,
"fullname": fullname,
"birthday" : birthday
});
});
}
void validateAndSubmit() async{
final form = formKey.currentState;
if (validateAndSave()) {
try {
if (_formType == FormType.login) {
String userId = await widget.auth.signInWithEmailAndPassword( _email.trim(), _password.trim());
} else {
String userId = await widget.auth.createUserWithEmailAndPassword( _email.trim(), _password.trim());
_addData(_email, _fullname, _birthday);
}
widget.onSignedIn();
}
catch (e)
{
print('Error: $e');
}
} else {
print('form is invalid');
}
}
void moveToRegister () {
formKey.currentState.reset();
setState(() {
_formType = FormType.register;
});
}
void moveToLogin () {
formKey.currentState.reset();
setState(() {
_formType = FormType.login;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Login"),
backgroundColor: const Color(0xFF86d2dd),
),
body: new Container(
padding: EdgeInsets.all(16.0),
child: new Form(
key: formKey,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: buildInputs() + buildSubmitButtons(),
)
)
)
);
}
List<Widget> buildInputs() {
if (_formType == FormType.login) {
return [
new TextFormField(
decoration: new InputDecoration(labelText: "Email"),
validator: (value) => value.isEmpty ? 'Email can\'t be empty' : null,
onSaved: (value) => _email = value,
),
new TextFormField(
decoration: new InputDecoration(labelText: "Password"),
obscureText: true,
validator: (value) => value.isEmpty ? 'Password can\'t be empty' : null,
onSaved: (value) => _password = value,
),
];
} else {
return [
new TextFormField(
decoration: new InputDecoration(labelText: "Email"),
validator: (value) => value.isEmpty ? 'Email can\'t be empty' : null,
onSaved: (value) => _email = value,
),
new TextFormField(
decoration: new InputDecoration(labelText: "Password"),
obscureText: true,
validator: (value) => value.isEmpty ? 'Password can\'t be empty' : null,
onSaved: (value) => _password = value,
),
new TextFormField(
decoration: new InputDecoration(labelText: "Name "),
validator: (value) => value.isEmpty ? 'Name can\'t be empty' : null,
onSaved: (value) => _fullname = value,
),
new TextFormField(
decoration: new InputDecoration(labelText: "Birthday (MM/DD)"),
validator: (value) => value.isEmpty ? 'Birthday can\'t be empty' : null,
onSaved: (value) => _birthday = value,
),
];
}
}
List<Widget> buildSubmitButtons() {
if (_formType == FormType.login) {
return [
new RaisedButton(
child: new Text('Login', style: new TextStyle(fontSize: 20.0)),
onPressed: validateAndSubmit,
),
new FlatButton(
child: new Text('Create an account', style: new TextStyle(fontSize: 20.0)),
onPressed: moveToRegister,
)
];
} else {
return [
new RaisedButton(
child: new Text('Create an account', style: new TextStyle(fontSize: 20.0)),
onPressed: validateAndSubmit,
),
new FlatButton(
child: new Text('Have an account? Login', style: new TextStyle(fontSize: 20.0)),
onPressed: moveToLogin,
)
];
}
}
}
I'm experimenting with InheritedWidget myself. After reading https://stackoverflow.com/a/51912243/7050833 I would try placing the UserProvider above the MaterialApp.
UserProvider(child: MaterialApp(...