I'm new in Flutter and have been trying to find a solution for this, but is there a way I can just accept the username ignoring if it's lowercase or uppercase? As long as it matches with their username it's fine to proceed.
Widget emailField() {
return TextFormField(
textInputAction: TextInputAction.next,
keyboardType: TextInputType.emailAddress,
focusNode: emailNode,
validator: validateEmpty,
decoration: InputDecoration(
hintText: 'Username',
prefixIcon: const Icon(Icons.account_circle),
labelStyle: Label,
fillColor: Colors.transparent,
),
//validator: validateEmail,
onSaved: (String? value) {
email = value as String;
},
);
}
submit() async {
if (formKey1.currentState!.validate()) {
formKey1.currentState!.save();
if (_prefs.userSession!.username == email) {
EasyLoading.instance.userInteractions = false;
EasyLoading.show(status: 'Deleting account...');
final response = await authService.masterDelete();
if (_prefs.userSession!.username != email) {
AwesomeDialog(
context: context,
dialogType: DialogType.ERROR,
title: 'ERROR',
desc: 'Incorrect username',
btnCancelText: 'Accept',
btnCancelOnPress: () {},
).show();
}
If it's only about ignoring lowercase/uppercase, then use toLowerCase() on both strings and compare them:
String mailOne = "TeSt123#gmail.com";
String mailTwo = "test123#gMAIL.com";
print(mailOne.toLowerCase() == mailOne.toLowerCase()); // -> true
Related
Im using email validator package on flutter to validate the email for login. I have one issue with this package that I want to allow spaces in the email when the user sign in because Im gonna trim the text anyway so I dont want it to show error when there is Spaces at the end.
child: TextFormField(
keyboardType: TextInputType.emailAddress,
controller: emailController,
cursorColor: Colors.white,
textInputAction: TextInputAction.next,
decoration: const InputDecoration(labelText: 'Email'),
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (email) =>
email != null && !EmailValidator.validate(email)
? 'Enter a valid Email' : null,
try {
await _auth.signInWithEmailAndPassword(
email: emailController.text.trim(),
password: passwordController.text.trim(),
);
Anyone knows how to do it or if there is a better way than using this package?
You don't need to use any package for validating email you can simply do it with RegExp like below in this space is allows and then you can trim it where ever you want to use
validator: (value) {
bool emailValid = RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(value!);
if (value == null || value.isEmpty) {
return 'Please Enter Email Address';
}else if (emailValid == false){
return 'Please Enter Valid Email Address';
}
return null;
},
Let me know if you have any questions. Thanks
You can trim email first then you can check for validation.
validator: (email) {
if(email != null) {
email = email.trim();
(!EmailValidator.validate(email))
? 'Enter a valid Email' : null,
}
return null;
}
best practice to use TextFormField validation is to not to allow user to put irrelevant data
TextFormField(
controller: _etcEmail,
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.done,
inputFormatter: [
// FilteringTextInputFormatter.allow(RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+")),
// FilteringTextInputFormatter.deny(RegExp(r" ")),
FilteringTextInputFormatter.allow(RegExp(r" ")),
],
hintText: 'Email',
validator: (value) {
if (value!.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
backgroundColor: Colors.pinkAccent,
behavior: SnackBarBehavior.floating,
padding: EdgeInsets.all(5),
content: (Text('Email Field is Required'))));
}
},
read: false,
)
i am beginner in flutter .
i have a probleme firebase auth with email work on all phones and emulators but on my new samsung phone it doesn't .
here is the error message
/FirebaseAuth( 2571): [FirebaseAuth:] Preparing to create service connection to fallback implementation
W/System ( 2571): Ignoring header X-Firebase-Locale because its value was null.
2
I/System.out( 2571): (HTTPLog)-Static: isSBSettingEnabled false
D/InputMethodManager( 2571): HSIFW - flag : 0
here is my auth screen where the user sign up or login.
import 'package:flutter/material.dart';
import 'package:m51/common/constants.dart';
import 'package:m51/common/loading.dart';
import 'package:m51/services/authentication.dart';
class AuthenticateScreen extends StatefulWidget {
#override
_AuthenticateScreenState createState() => _AuthenticateScreenState();
}
class _AuthenticateScreenState extends State<AuthenticateScreen> {
final AuthenticationService _auth = AuthenticationService();
final _formKey = GlobalKey<FormState>();
String error = '';
bool loading = false;
final emailController = TextEditingController();
final nameController = TextEditingController();
final passwordController = TextEditingController();
bool showSignIn = true;
#override
void dispose() {
nameController.dispose();
emailController.dispose();
passwordController.dispose();
super.dispose();
}
void toggleView() {
setState(() {
_formKey.currentState?.reset();
error = '';
emailController.text = '';
nameController.text = '';
passwordController.text = '';
showSignIn = !showSignIn;
});
}
#override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.blueGrey,
elevation: 0.0,
title: Text(showSignIn ? 'Sign in to Water Social' : 'Register to Water Social'),
actions: <Widget>[
TextButton.icon(
icon: Icon(
Icons.person,
color: Colors.white,
),
label: Text(showSignIn ? "Register" : 'Sign In',
style: TextStyle(color: Colors.white)),
onPressed: () => toggleView(),
),
],
),
body: Container(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 30.0),
child: Form(
key: _formKey,
child: Column(
children: [
!showSignIn
? TextFormField(
controller: nameController,
decoration: textInputDecoration.copyWith(hintText: 'name'),
validator: (value) =>
value == null || value.isEmpty ? "Enter a name" : null,
)
: Container(),
!showSignIn ? SizedBox(height: 10.0) : Container(),
TextFormField(
controller: emailController,
decoration: textInputDecoration.copyWith(hintText: 'email'),
validator: (value) =>
value == null || value.isEmpty ? "Enter an email" : null,
),
SizedBox(height: 10.0),
TextFormField(
controller: passwordController,
decoration: textInputDecoration.copyWith(hintText: 'password'),
obscureText: true,
validator: (value) => value != null && value.length < 6
? "Enter a password with at least 6 characters"
: null,
),
SizedBox(height: 10.0),
ElevatedButton(
child: Text(
showSignIn ? "Sign In" : "Register",
style: TextStyle(color: Colors.white),
),
onPressed: () async {
if (_formKey.currentState?.validate() == true) {
setState(() => loading = true);
var password = passwordController.value.text;
var email = emailController.value.text;
var name = nameController.value.text;
dynamic result = showSignIn
? await _auth.signInWithEmailAndPassword(email, password)
: await _auth.registerWithEmailAndPassword(name, email, password);
if (result == null) {
print ('Please supply a valid email');
}
}
}
),
SizedBox(height: 10.0),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 15.0),
)
],
),
),
),
);
}
}
i also have that message
I/flutter ( 4866): [firebase_auth/invalid-email] The email address is
badly formatted.
the service code
import 'package:firebase_auth/firebase_auth.dart';
import 'package:urjob/models/user.dart';
import 'package:urjob/services/database.dart';
class AuthenticationService {
final FirebaseAuth _auth = FirebaseAuth.instance;
AppUser? _userFromFirebaseUser(User? user) {
return user != null ? AppUser(user.uid) : null;
}
Stream<AppUser?> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
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 (exception) {
print(exception.toString());
return null;
}
}
Future registerWithEmailAndPassword(String name, String email, String password, String profilepic) async {
try {
UserCredential result =
await _auth.createUserWithEmailAndPassword(email: email, password: password);
User? user = result.user;
if (user == null) {
throw Exception("No user found");
} else {
await DatabaseService(user.uid).saveUser(name,profilepic,email);
return _userFromFirebaseUser(user);
}
} catch (exception) {
print(exception.toString());
return null;
}
}
Future signOut() async {
try {
return await _auth.signOut();
} catch (exception) {
print(exception.toString());
return null;
}
}
Future sendreset(String email) async {
try {
return await _auth.sendPasswordResetEmail(email: email);
} catch (exception) {
print(exception.toString());
return null;
}
}
}
Thank you for your help
i found the solution
we need in ma case to add .trim() functions to erase white spaces
https://github.com/FirebaseExtended/flutterfire/issues/1760
Trim text gotten from textfields.
emailController.text.trim(),
passwordController.text.trim()
I updated my Flutter app to Flutter 2, and now when I try to get the snapshot.error in my StreamBuider I get this
These are validators with Streams.
class LoginStreams with Validators {
dispose() {
_emailController.close();
_passwordController.close();
}
Function(String) get emailOnChange => _emailController.sink.add;
Function(String) get passwordOnChange => _passwordController.sink.add;
final _emailController = StreamController<String>.broadcast();
final _passwordController = StreamController<String>.broadcast();
Stream<String> get emailStream =>
_emailController.stream.transform(emailValidator);
Stream<String> get passwordStream =>
_passwordController.stream.transform(passwordValidator);
}
--
class Validators {
final passwordValidator = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink) {
password.length >= 5
? sink.add(password)
: sink.addError("La contraseña debe contener más de 5 caracteres");
});
final emailValidator =
StreamTransformer<String, String>.fromHandlers(handleData: (email, sink) {
if (email.contains('#') && email.contains('.')) {
sink.add(email);
} else {
sink.addError("Ingrese un email válido");
}
});
}
StreamBuilder(
stream: _validators.emailStream,
builder: (BuildContext context, AsyncSnapshot snapshot)=>TextField(
keyboardType: TextInputType.emailAddress,
controller: emailController,
decoration: InputDecoration(
errorText: '$snapshot.error',
labelText: widget.loginModel.emailTextfield,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(CmbSpacing.SpaceMD))),
onChanged: _validators.emailOnChange,
),
),
SizedBox(height: CmbSpacing.SpaceSM),
StreamBuilder(
stream: _validators.passwordStream,
builder: (BuildContext context, AsyncSnapshot snapshot)=>TextField(
controller: passwordController,
obscureText: true,
decoration: InputDecoration(
errorText: '$snapshot.error',
suffixIcon: Icon(Icons.visibility_off_outlined),
labelText: widget.loginModel.passwordTextfield,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(CmbSpacing.SpaceMD))),
onChanged: _validators.passwordOnChange,
),
),
If someone could help me i would be so gratefull, I am so confused because after upgrading to Flutter 2 this used to work great.
It's something new about StreamBuilders in Flutter 2?
EDIT:
I changed "$snapshot.error" to snapshot.error.toString()
and now I get null.
You're not interpolating the error correctly.
If you want to call an extra method before interpolating, you have to wrap the expression in ${}, e.g. '${snapshot.error}. In your case you're just appending .error to a string representation of snapshot
Replace
errorText: '$snapshot.error'
With
errorText: snapshot.error?.toString()
// or if you want to use it in a sentence
errorText: "This is the error: ${snapshot.error}"
You have to apply condition statement overthere:
errorText: snapshot.hasError ? '${snapshot.error}' : null
I'm sure this will help. :)
Whenever I tried to do login and tap on the login button then I am having this type of problem with the null check operator used on null values.
This is the error message that I got:
════════ Exception caught by gesture ═══════════════════════════════════════════
The following _CastError was thrown while handling a gesture:
Null check operator used on a null value
When the exception was thrown, this was the stack
#0 _AuthFormState._trySubmit package://FlutterChat/widgets/auth_form.dart:46
#1 _InkResponseState._handleTap
#2 GestureRecognizer.invokeCallback
#3 TapGestureRecognizer.handleTapUp
#4 BaseTapGestureRecognizer._checkUp
Handler: "onTap"
Recognizer: TapGestureRecognizer#c9833
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(165.5, 228.0)
finalLocalPosition: Offset(19.0, 13.5)
button: 1
sent tap down
This is my auth_form.dart file:
import 'package:flutter/material.dart';
import 'dart:io';
import './user_image_picker.dart';
class AuthForm extends StatefulWidget {
AuthForm(this.submitFn, this.isLoading);
final bool isLoading;
final Future<void> Function(String email, String password, String username,
File image, bool isLogin, BuildContext ctx) submitFn;
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
dynamic _userEmail = '';
dynamic _userName = '';
dynamic _userPassword;
File? _userImageFile;
void _pickedImage(File? image) {
_userImageFile = image;
}
//Form validation and save
_trySubmit() {
final isValid = _formKey.currentState?.validate();
FocusScope.of(context).unfocus();
if (_userImageFile == null && !_isLogin) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Please Select an Image'),
backgroundColor: Theme.of(context).errorColor,
));
return;
}
if (isValid!) {
_formKey.currentState?.save();
widget.submitFn(
_userEmail?.trim(),
_userPassword?.trim(),
_userName?.trim(),
_userImageFile!,
_isLogin,
context,
);
}
}
//Form Widget
#override
Widget build(BuildContext context) {
return new Builder(
builder: (context) {
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
if (!_isLogin) UserImagePicker(_pickedImage),
TextFormField(
key: ValueKey('email'),
autocorrect: false,
textCapitalization: TextCapitalization.none,
enableSuggestions: false,
validator: (value) {
if (value?.isEmpty == null || !value!.contains('#')) {
return 'Please Enter valid Email Address.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address',
),
onSaved: (value) {
_userEmail = value;
},
),
if (!_isLogin)
TextFormField(
key: ValueKey('username'),
autocorrect: true,
textCapitalization: TextCapitalization.words,
enableSuggestions: false,
validator: (value) {
if (value!.isEmpty) {
return 'Please Enter Username.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Username',
),
onSaved: (value) {
_userName = value;
}),
TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value?.isEmpty == null || value!.length < 7) {
return 'Password must be atleast 7 characters long';
}
return null;
},
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
),
onSaved: (value) {
_userPassword = value;
}),
SizedBox(
height: 12,
),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
ElevatedButton(
child: Text(_isLogin ? 'Login' : 'Signup'),
onPressed: _trySubmit,
),
if (!widget.isLoading)
TextButton(
child: Text(_isLogin
? 'Create a new account'
: 'I already have an account'),
style: TextButton.styleFrom(primary: Colors.pink),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
],
),
),
),
),
),
);
},
);
}
}
This is my auth_screen.dart file:
import 'package:FlutterChat/screens/conversion_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../widgets/auth_form.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
//import 'package:firebase_core/firebase_core.dart';
class AuthScreen extends StatefulWidget {
#override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
//FirebaseAuth _auth = FirebaseAuth.instance;
var _isLoading = false;
//Submit AuthCredential Function
Future<void> submitAuthForm(String? email, String? password, String? username,
File? image, bool isLogin, BuildContext ctx) async {
UserCredential userCredential;
try {
setState(() {
_isLoading = true;
});
if (isLogin) {
userCredential = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email!, password: password!);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversionScreen()));
} else {
userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email!, password: password!);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversionScreen()));
final ref = FirebaseStorage.instance
.ref()
.child('user_image')
.child(userCredential.user!.uid + '.jpg');
await ref.putFile(image!).whenComplete(() => print('Image Upload'));
final url = await ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('users')
.doc(userCredential.user?.uid)
.set({
'username': username,
'email': email,
'imageUrl': url,
});
}
} on PlatformException catch (error) {
dynamic message = 'An error occured, please check your credentials!';
if (error.message != null) {
message = error.message;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Theme.of(ctx).errorColor,
),
);
setState(() {
_isLoading = false;
});
} catch (error) {
print(error);
setState(() {
_isLoading = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: AuthForm(submitAuthForm, _isLoading),
);
}
}
If someone knows then please help me.
The error is occurring due to this line,
_userImageFile!,
What I suspect is that your if clause,
if (_userImageFile == null && !_isLogin) {
is not protecting it from not being null, since the if clause would be false if _isLogin is true despite _userImageFile being null.
One way to fix this would be to do remove the bang operator since you can also have a case of calling the submitFn when your _isLogin is true and in that case, you definitely won't have a non null _userImageFile.
_userImageFile, // while calling widget.submitFn
Then make sure you change your `submitFn' function type to
final Future<void> Function(String email, String password, String username,
// add the ? for File image
File? image, bool isLogin, BuildContext ctx) submitFn;
Since your, submitAuthForm already says File? image, nothing to change there.
in auth_form.dart,use this process..check the image enter image description here
In my app the user has to insert a name in the textformfield. While the user is writing a query should be made to the database, that controls if the name already exists. This query returns the number of how many times the name exists. Till now I am able to make it when I press a button.
This is the function that returns the count of the names:
checkRecipe(String name) async{
await db.create();
int count = await db.checkRecipe(name);
print("Count: "+count.toString());
if(count > 0) return "Exists";
}
And this is the TextFormField, which should be validated async:
TextField(
controller: recipeDescription,
decoration: InputDecoration(
hintText: "Beschreibe dein Rezept..."
),
keyboardType: TextInputType.multiline,
maxLines: null,
maxLength: 75,
validator: (text) async{ //Returns an error
int count = await checkRecipe(text);
if (count > 0) return "Exists";
},
)
The error of the code is:
The argument type Future can't be assigned to the parameter type
String
I do know what the error means. But I do not know how to work around could look like. It would be awesome if somebody could help me.
I have found a solution.
My Code looks now like this:
//My TextFormField validator
validator: (value) => checkRecipe(value) ? "Name already taken" : null,
//the function
checkRecipe<bool>(String name) {
bool _recExist = false;
db.create().then((nothing){
db.checkRecipe(name).then((val){
if(val > 0) {
setState(() {
_recExist = true;
});
} else {
setState(() {
_recExist = false;
});
}
});
});
return _recExist;
}
Perhaps you could run your async check using the onChange handler and set a local variable to store the result.
Something like:
TextFormField(
controller: recipeDescription,
decoration: InputDecoration(hintText: "Beschreibe dein Rezept..."),
keyboardType: TextInputType.multiline,
maxLines: null,
maxLength: 75,
onChanged: (text) async {
final check = await checkRecipe(text);
setState(() => hasRecipe = check);
},
validator: (_) => (hasRecipe) ? "Exists" : null,
)
I wanted a same behavior for one of our apps and ended up writing a widget (which I recently published to pub.dev).
AsyncTextFormField(
controller: controller,
validationDebounce: Duration(milliseconds: 500),
validator: isValidPasscode,
hintText: 'Enter the Passcode')
You can pass in a Future<bool> function for the validator and set an interval before the text is sent to server.
The code is available on github.