i am a newbie to Flutter and I am building a Flutter mobile app, i don't why i can't post the data from my Sign Up form to the Authentication in fireBase ,
It is my Auth class ----------------------------------------------------------------------------
class Auth with ChangeNotifier {
late String _token;
late DateTime _expirytDate;
late String _userId;
Future<void> signup(String email, String password) async {
const url =
'https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=AIzaSyDL5WN64rhcYbYbiLutVA33Ekjixj0M3BE';
final response = await http.post(Uri.parse(url),
body: json.encode({
'email': email,
'password': password,
'returnSecureToken': true,
}));
}
}
Here is my AuthCard Class
class AuthCard extends StatefulWidget {
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard> {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
Future<void> _submit() async {
if (!_formKey.currentState!.validate()) {
// Invalid!
return;
}
_formKey.currentState!.save();
setState(() {
_isLoading = true;
});
if (_authMode == AuthMode.Login) {
// Log user in
} else {
// Sign user up
await Provider.of<Auth>(context).signup(_authData['email']! ,_authData['password']! );
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
} else {
setState(() {
_authMode = AuthMode.Login;
});
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: Container(
height: _authMode == AuthMode.Signup ? 320 : 260,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 320 : 260),
width: deviceSize.width * 0.75,
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty || !value.contains('#')) {
return 'Invalid email!';
}
return null;
},
onSaved: (value) {
_authData['email'] = value!;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return 'Password is too short!';
}
},
onSaved: (value) {
_authData['password'] = value!;
},
),
if (_authMode == AuthMode.Signup)
TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
}
}
: null,
),
SizedBox(
height: 20,
),
if (_isLoading)
CircularProgressIndicator()
else
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
child: Text(
_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
),
),
TextButton(
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} INSTEAD'),
),
onPressed: _switchAuthMode,
style: TextButton.styleFrom(primary: Colors.amber),
),
],
),
),
),
),
);
}
}
Here is my Error and I don't understand the error.
Error: Assertion failed:
file:///C:/Users/DELL/development/SDK/flutter/.pub-cache/hosted/pub.dartlang.org/provider-6.0.3/lib/src/provider.dart:274:7
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw_
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3 assertFailed
packages/provider/src/provider.dart 276:11
of
packages/flutter_application_1/screens/auth_screen.dart 114:40
_submit
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:5 _async
packages/flutter_application_1/screens/auth_screen.dart 101:23
[_submit]
packages/flutter/src/material/ink_well.dart 1072:21
handleTap
packages/flutter/src/gestures/recognizer.dart 253:24
invokeCallback
packages/flutter/src/gestures/tap.dart 627:11
handleTapUp
packages/flutter/src/gestures/tap.dart 306:5
[_checkUp]
packages/flutter/src/gestures/tap.dart 239:7
handlePrimaryPointer
packages/flutter/src/gestures/recognizer.dart 615:9
handleEvent
packages/flutter/src/gestures/pointer_router.dart 98:12
[_dispatch]
packages/flutter/src/gestures/pointer_router.dart 143:9
<fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:13 forEach
packages/flutter/src/gestures/pointer_router.dart 141:17
[_dispatchEventToRoutes]
packages/flutter/src/gestures/pointer_router.dart 127:7
route
packages/flutter/src/gestures/binding.dart 460:19
handleEvent
packages/flutter/src/gestures/binding.dart 440:14
dispatchEvent
packages/flutter/src/rendering/binding.dart 337:11
dispatchEvent
packages/flutter/src/gestures/binding.dart 395:7
[_handlePointerEventImmediately]
packages/flutter/src/gestures/binding.dart 357:5
handlePointerEvent
packages/flutter/src/gestures/binding.dart 314:7
[_flushPointerEventQueue]
packages/flutter/src/gestures/binding.dart 295:7
[_handlePointerDataPacket]
C:/b/s/w/ir/cache/builder/src/out/host_debug/flutter_web_sdk/lib/_engine/engine/platform_dispatcher.dart 1183:13 invoke1
You must use Try-Catch Block when interacting with Futures and await.
2ndly when you are passing the email and password to the Auth class signup function make it clear with Cast that which value you are passing.
See the snippet below with firebase signup entry
class AuthCard extends StatefulWidget {
const AuthCard({super.key});
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard> {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
Future<void> _submit() async {
if (!_formKey.currentState!.validate()) {
// Invalid!
return;
}
_formKey.currentState!.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
// return;
} else {
await Provider.of<Auth>(context, listen: false).userSignUp(
_authData['email'] as String,
_authData['password'] as String,
);
}
} catch (error) {
print(error);
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
} else {
setState(() {
_authMode = AuthMode.Login;
});
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: Container(
height: _authMode == AuthMode.Signup ? 320 : 260,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 320 : 260),
width: deviceSize.width * 0.75,
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty || !value.contains('#')) {
return 'Invalid email!';
}
return null;
},
onSaved: (value) {
_authData['email'] = value!;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return 'Password is too short!';
}
},
onSaved: (value) {
_authData['password'] = value!;
},
),
if (_authMode == AuthMode.Signup)
TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
}
}
: null,
),
SizedBox(
height: 20,
),
if (_isLoading)
CircularProgressIndicator()
else
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
child: Text(
_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
),
),
TextButton(
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} INSTEAD'),
),
onPressed: _switchAuthMode,
style: TextButton.styleFrom(primary: Colors.amber),
),
],
),
),
),
),
);
}
}
Here is the signup data posted to the firebase.
Related
I am trying to get a barcode to scan an item and retrieve the item from cloud firestore database. The application is meant to then display the item onto the homepage.
But i keep having the same error.
I have tried to change it to Map<Dynamic, Dynamic>. I have also tried to remove it from not being null Map<String, dynamic> no question mark. All flutter lib are up to date as well as the pubspec.
The code below is for my homepage
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/services.dart';
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
Map<String, dynamic>? mapProducts = {};
//Initialize
#override
void initState() {
if (userProfile.containsKey("Unordered Products")) {
mapProducts = userProfile["Unordered Products"];
}
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
double size =
MediaQuery.of(context).size.width < MediaQuery.of(context).size.height
? MediaQuery.of(context).size.width
: (!kIsWeb)
? MediaQuery.of(context).size.height
: MediaQuery.of(context).size.height / 2;
//For Refreshing the theme
if (userProfile.containsKey("Theme")) {
myAppTheme = userProfile["Theme"] == "Light Theme"
? getMainThemeWithBrightness(context, Brightness.light)
: getMainThemeWithBrightness(context, Brightness.dark);
}
MobileScannerController cameraController = MobileScannerController();
return SafeArea(
child: Scaffold(
key: scaffoldKey,
backgroundColor: myAppTheme?.scaffoldBackgroundColor,
appBar: getAppBar(
scaffoldKey: scaffoldKey,
context: context,
strAppBarTitle: "Spar Store",
showBackButton: false,
),
//drawer
drawer: getDrawer(context, scaffoldKey),
floatingActionButton: FloatingActionButton(
backgroundColor: myAppTheme?.primaryColor,
onPressed: () async {
String? barcode = await scan();
if (barcode != null && barcode != "") {
if (mapProducts!.containsKey(barcode)) {
//Increase count
setState(() {
mapProducts![barcode] = ++mapProducts![barcode];
});
} else {
//Add a new product
setState(() {
mapProducts![barcode] = 1;
});
}
userProfile["Unordered Products"] = mapProducts;
//Update the new Unordered Products list to the Firebase CLoud Firestpre
await authService.setData();
}
},
child: Icon(Icons.add, color: myAppTheme?.iconTheme.color),
),
//Body
body: mapProducts != null && mapProducts!.length > 0
? Column(
children: <Widget>[
//Products in Cart List
getUnorderedProducts(size),
//Final invoice
getInvoice(size),
//Checkout Button
getCheckoutButton(size),
],
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
"assets/images/empty-cart.png",
fit: BoxFit.fitWidth,
),
Text(
"No Items Added.\nPlease Add items by scanning them",
style: myAppTheme?.textTheme.caption,
textAlign: TextAlign.center,
),
],
),
),
),
);
}
//Get the list of all the Orders still in Cart
getUnorderedProducts(double size) {
return SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.7,
child: ListView.builder(
itemCount: mapProducts!.length,
itemBuilder: (context, index) {
return FutureBuilder(
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null || snapshot.hasData == false) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
myAppTheme!.primaryColor),
strokeWidth: 5,
),
);
} else {
Map<String, dynamic>? mapProduct = snapshot.data;
return GestureDetector(
child: Card(
elevation: myAppTheme?.cardTheme.elevation,
color: myAppTheme?.cardTheme.color,
shape: myAppTheme?.cardTheme.shape,
child: Row(
children: <Widget>[
mapProduct!.containsKey("photo url")
? ClipRRect(
borderRadius: BorderRadius.circular(15),
child: SizedBox(
width: 120,
child: Image.network(
mapProduct["photo url"][0])))
: Icon(
Icons.category,
color: myAppTheme?.iconTheme.color,
),
SizedBox(
width: size - 150,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
//Title
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
mapProduct["name"],
style: myAppTheme?.textTheme.caption,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.right,
),
),
//Model
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(mapProduct["model"],
style: myAppTheme?.textTheme.bodyText1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.right),
),
//Discount
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Discount: ${mapProduct["discount"]}%",
style: myAppTheme?.textTheme.bodyText1
?.copyWith(
fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.right),
),
//Price
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Price: ${mapProduct["price"]}",
style: myAppTheme?.textTheme.bodyText1
?.copyWith(
fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.right),
),
//Quantity
Container(
padding: const EdgeInsets.all(8.0),
height: 60,
child: StepperTouch(
initialValue:
mapProducts?.values.elementAt(index),
direction: Axis.horizontal,
withSpring: true,
primaryColor:
myAppTheme?.colorScheme.secondary,
textColor:
myAppTheme?.textTheme.bodyText1?.color,
onChanged: (int value) {
if (value == 0) {
setState(() {
mapProducts?.remove(mapProducts?.keys
.elementAt(index));
});
} else if (value > 0) {
setState(() {
mapProducts![mapProducts!.keys
.elementAt(index)] = value;
});
}
userProfile["Unordered Products"] =
mapProducts;
},
),
),
],
),
),
],
),
),
//Open
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ViewProductScreen(mapProduct)),
);
},
);
}
},
future: getProduct(mapProducts!.keys.elementAt(index)),
);
}),
);
}
//Get the Total Price and the Total discount
getInvoice(double size) {
return FutureBuilder(
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot == null ||
snapshot.data == null ||
snapshot.hasData == false) {
return Center(
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(myAppTheme!.primaryColor),
strokeWidth: 5,
),
);
} else {
Map mapProduct = snapshot.data;
double dbTotalDiscount = mapProduct["discount"],
dbTotalPrice = mapProduct["price"];
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
//Total Price
Padding(
padding: const EdgeInsets.fromLTRB(0, 5, 10, 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
"Total Price: ",
style: myAppTheme?.textTheme.bodyText1,
overflow: TextOverflow.ellipsis,
),
Text(
dbTotalPrice.toString(),
style: myAppTheme?.textTheme.bodyText1,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
);
}
},
future: getInvoiceDetails(),
);
}
getInvoiceDetails() async {
double dbTotalDiscount = 0.0, dbTotalPrice = 0.0;
//Loop through all the products to get the Discount and the Price
await Future.forEach(mapProducts!.keys, (key) async {
String strProductID = key;
Map<String, dynamic>? mapProduct =
(await getProduct(strProductID)) as Map<String, dynamic>?;
if (mapProduct!.containsKey("discount")) {
dbTotalDiscount += double.tryParse(
(mapProduct["discount"] * mapProducts![key]).toString())!;
}
if (mapProduct.containsKey("price")) {
dbTotalPrice += double.tryParse(
(mapProduct["price"] * mapProducts![key]).toString())!;
}
// print("discount: " + dbTotalDiscount.toString());
// print("price: " + dbTotalPrice.toString());
});
return {"discount": dbTotalDiscount, "price": dbTotalPrice};
}
//Get Checkout button
getCheckoutButton(double size) {
return ButtonTheme(
minWidth: double.infinity,
child: Padding(
padding: const EdgeInsets.fromLTRB(80, 20, 80, 10),
child: primaryRaisedButton(
context: context,
text: "Checkout now",
color: myAppTheme?.primaryColor,
onPressed: () async {
//Go to Checkout
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => CheckoutScreen()),
);
setState(() {
//Refresh the UI after returning back from the Checkout screen
mapProducts = userProfile["Unordered Products"];
});
},
),
),
);
}
//=================================================================================
//Get details of product
Future<Map<String, dynamic>? Function()> getProduct(String barcode) async {
return (await FirebaseFirestore.instance
.collection("Products")
.doc(barcode)
.get())
.data;
}
//Scan QR code
Future<String?> scan() async {
try {
String barcode = (await FlutterBarcodeScanner.scanBarcode(
'#ff6666', 'Cancel', true, ScanMode.QR));
return barcode;
} on PlatformException catch (e) {
if (e.code == BarcodeScanner.cameraAccessDenied) {
showSnackBar(
scaffoldKey: scaffoldKey,
text: "The user did not grant the camera permission!",
buttonText: '',
onPressed: () {});
} else {
showSnackBar(
scaffoldKey: scaffoldKey,
text: "Unknown error: $e",
buttonText: '',
onPressed: () {});
}
return null;
} on FormatException {
showSnackBar(
scaffoldKey: scaffoldKey,
text:
'null (User returned using the "back"-button before scanning anything. Result)',
buttonText: '',
onPressed: () {});
} catch (e) {
showSnackBar(
scaffoldKey: scaffoldKey,
text: "Unknown error: $e",
buttonText: '',
onPressed: () {});
}
return null;
}
}
If anyone can help would be great as i am a beginner and it is for a school project.
replace your getProduct() method with this:
Future<Map<String, dynamic>?> getProduct(String barcode) async {
return (await FirebaseFirestore.instance
.collection("Products")
.doc(barcode)
.get())
.data() ;
}
I am new to flutter and cant understand why its giving me an error in routing, my login page
class _LoginPageState extends State<LoginPage> {
final _key = GlobalKey<FormState>();
String uid = "";
bool onLog = false;
toCat() async{
if(_key.currentState!.validate()){
setState(() {
onLog = true;
});
await Future.delayed(Duration(milliseconds: 1000));
Navigator.pushNamed(context, MyRoutes.catPage);
setState(() {
onLog = false;
});
}
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Form(
key: _key,
child: Column(
children: [
SizedBox(height: 50,),
Image.network('https://www.pngkit.com/png/full/6-60441_welcome-welcome-png.png', fit: BoxFit.cover,),
SizedBox(height: 20,),
Text('Hi, $uid', style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),),
SizedBox(height: 20,),
Padding(
padding: EdgeInsets.all(30),
child: Column(
children: [
TextFormField(
decoration: InputDecoration(hintText: 'Enter username', labelText: 'Username'),
onChanged: (value){
uid = value;
setState(() {});
},
),
TextFormField(
obscureText: true,
decoration: InputDecoration(hintText:'Enter password', labelText: 'Password'),
validator: (value) {
if(value!.isEmpty){
return 'password must not be empty';
}else if(value.length < 6){
return 'passowrd cannot be small';
}else{return null;}
},
),
SizedBox(height: 25,),
InkWell(
onTap: (){toCat();},
child: AnimatedContainer(
alignment: Alignment.center,
duration: Duration(milliseconds: 300),
height: 50,
width: onLog ? 50 : 150,
decoration: BoxDecoration(color: Colors.cyan, borderRadius: BorderRadius.circular(onLog ? 50 : 8),),
child: onLog ? Icon(Icons.done) : Text('Login', style: TextStyle(color: Colors.black, fontSize: 20,),textScaleFactor: 1.2,),
),
onTap function in Inkwell widget , i wanna go to this page
class _CatPageState extends State<CatPage> {
Future<ModelClass> getImage() async {
final Uri uri = Uri.parse("https://aws.random.cat/meow");
final response = await (http.get(uri));
if(response.statusCode == 200){
final jsonData = jsonDecode(response.body);
return ModelClass.fromJson(jsonData);
}
else{
throw Exception;
}
}
#override
Widget build(BuildContext context) {
return Center(
child: FutureBuilder<ModelClass>(future: getImage(),builder: (context, snapshot) {
if (snapshot.hasData){
final cat = snapshot.data;
return Container(
height: 400,
width: 400,
decoration: BoxDecoration(image: DecorationImage(image: NetworkImage(cat!.url), fit: BoxFit.cover,),),
);
}else if(snapshot.hasError){
return Text(snapshot.error.toString());
}
return CircularProgressIndicator();
}
either that error in the title or this
Could not find a generator for route RouteSettings
or this
Navigator operation requested with a context that does not include a Navigator.
i cant understand routing
I managed to fix the problem with the following:
Nav()
{ Navigator.push(context, MaterialPageRoute(builder: (context) => LoginForm())); setState(){};
}
I am trying to use setState class inside the floating action button but, setState class is not able to rerender the ui.Here is my code:
Here i use isLogin bool type variable so it able to toggle the two different ui.In fact the is not abe to working when ever the setState function call it must change the value of that variable is rerender the ui but it is not working .
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class AuthForm extends StatefulWidget {
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
#override
Widget build(BuildContext context) {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail = '';
var _userName = '';
var _userPassword = '';
void _trySubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState.save();
print(_userEmail);
print(_userPassword);
print(_userName);
}
}
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please enter the valid email address.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address',
),
onSaved: (newValue) {
_userEmail = newValue;
},
),
TextFormField(
validator: (value) {
if (value.isEmpty || value.length < 4) {
return 'Please enter at least 4 character.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Username',
),
onSaved: (newValue) {
_userName = newValue;
},
),
TextFormField(
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Password must be at least 7 character long.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Password',
),
obscureText: true,
onSaved: (newValue) {
_userPassword = newValue;
},
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
_trySubmit();
},
child: Text(
_isLogin ? 'Login' : 'Signup',
),
),
FlatButton(
textColor: Theme.of(context).primaryColor,
child: Text(
_isLogin
? 'Create New Account.'
: 'I Already Have Account.',
),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
],
),
),
),
),
),
);
}
}
The problem is with the var _isLogin = true; you have defined it inside the build method that's why whenever the setState is called it becomes true and does not change the ui.
Try placing it outside the build method.
Example below:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return AuthForm();
}
}
class AuthForm extends StatefulWidget {
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
var _isLogin = true;
#override
Widget build(BuildContext context) {
final _formKey = GlobalKey<FormState>();
var _userEmail = '';
var _userName = '';
var _userPassword = '';
void _trySubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState.save();
print(_userEmail);
print(_userPassword);
print(_userName);
}
}
return MaterialApp(
home: Scaffold(
body: Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please enter the valid email address.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address',
),
onSaved: (newValue) {
_userEmail = newValue;
},
),
TextFormField(
validator: (value) {
if (value.isEmpty || value.length < 4) {
return 'Please enter at least 4 character.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Username',
),
onSaved: (newValue) {
_userName = newValue;
},
),
TextFormField(
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Password must be at least 7 character long.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Password',
),
obscureText: true,
onSaved: (newValue) {
_userPassword = newValue;
},
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
_trySubmit();
},
child: Text(
_isLogin ? 'Login' : 'Signup',
),
),
FlatButton(
textColor: Theme.of(context).primaryColor,
child: Text(
_isLogin
? 'Create New Account.'
: 'I Already Have Account.',
),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
],
),
),
),
),
),
),
),
);
}
}
Let me know if it works.
Everyone I am new in flutter. How can create loading screen on login page. when i click on login button then it should be redirect on Dashboard with loading screen. I am trying to create loading screen in flutter. When I click on login button then loading screen show be show and after loading screen it should be redirect on Dashboard.....
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutternew/dashboard.dart';
import 'package:flutternew/forget_password.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'bezierContainer.dart';
class Home extends StatefulWidget {
Home({Key key, this.title}) : super(key: key);
final String title;
#override
_HomeState createState() => _HomeState();
}
class ShowLoading extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Loading View'),
),
body: Center(
child: _circularProgressIndicator(),
));
}
Widget _circularProgressIndicator() {
return CircularProgressIndicator();
}
}
class _HomeState extends State<Home> {
bool _isLoading = false;
GlobalKey<FormState> _formKey = GlobalKey<FormState>(debugLabel: '_homekey');
final _scaffoldKey = GlobalKey<ScaffoldState>();
String _email;
String _password;
final TextEditingController emailController = new TextEditingController();
final TextEditingController passwordController = new TextEditingController();
var modal = Container();
showAlertDialog(BuildContext context, String message) {
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
AlertDialog alert = AlertDialog(
title: Text("Error"),
content: Text(message),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Widget _formSetupWidget(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: emailController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Username",
hintStyle: TextStyle(color: Colors.grey, fontSize: 25),
fillColor: Color(0xFFFAFAfA),
filled: true),
keyboardType: TextInputType.emailAddress,
validator: (val) {
if (val.length == 0)
return "Please enter email";
else if (!val.contains("#"))
return "Please enter valid email";
else
return null;
},
onSaved: (val) => _email = val,
),
SizedBox(
height: 15,
),
TextFormField(
controller: passwordController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Password",
hintStyle: TextStyle(color: Colors.grey, fontSize: 25),
fillColor: Color(0xFFFAFAfA),
filled: true),
obscureText: true,
validator: (val) {
if (val.length == 0)
return "Please enter password";
else if (val.length <= 5)
return "Your password should be more then 6 char long";
else
return null;
},
onSaved: (val) => _password = val,
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
),
ButtonTheme(
minWidth: 500.0,
height: 60.0,
child: RaisedButton(
child: new Text("Login",
style: TextStyle(color: Colors.white, fontSize: 23.0)),
color: Colors.blueAccent,
highlightColor: Colors.blueAccent,
onPressed: () {
if (emailController.text != " " ||
passwordController.text != " ") {
signIn(emailController.text, passwordController.text);
}
},
),
),
],
),
);
}
signIn(String email, pass) async {
int visible = 0;
final sharedPreferences = await SharedPreferences.getInstance();
Map data = {'email': email, 'password': pass};
var jsonResponse = null;
var response = await http
.post("https://abcdef.com/iot/api/login", body: data);
if (response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if (jsonResponse != null) {
if (jsonResponse['success'] == 1) {
sharedPreferences.setString("token", jsonResponse['data']['token']);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext context) => Dashboard()),
(Route<dynamic> route) => false);
} else {
String message = jsonResponse['message'];
showAlertDialog(context, message);
}
}
} else {
setState(() {
_isLoading = false;
});
print(response.body);
}
}
#override
Widget build(BuildContext context) {
Center(
child: SpinKitWave(color: Colors.white, type: SpinKitWaveType.start),
);
var assetsImage = new AssetImage('assets/logo.png');
var image = new Image(image: assetsImage, width: 150.0, height: 150.0);
final height = MediaQuery.of(context).size.height;
return Scaffold(
body: Container(
height: height,
color: Colors.white,
child: Stack(
children: <Widget>[
Positioned(
top: -height * .15,
right: -MediaQuery.of(context).size.width * .4,
child: BezierContainer()),
Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 70),
new Center(
child: image,
),
SizedBox(height: 20),
_formSetupWidget(context),
Container(
padding: EdgeInsets.symmetric(vertical: 10),
alignment: Alignment.centerRight,
child: FlatButton(
child: Text("Forgot Password?"),
onPressed: () {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (BuildContext context) =>
Forget_password()),
(Route<dynamic> route) => false);
},
),
),
SizedBox(height: height * .055),
],
),
),
),
],
),
));
}
}
Create class
class LoaderDialog {
static Future<void> showLoadingDialog(BuildContext context, GlobalKey key) async {
var wid = MediaQuery.of(context).size.width / 2;
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.only(left: 130 , right: 130),
child: Dialog(
key: key,
backgroundColor: Colors.white,
child: Container(
width: 60.0,
height: 60.0,
child: Image.asset(
'images/loaderOld.gif',
height: 60,
width: 60,
),
)
),
);
},
);
}
}
How to Call:
In your Class(Where you want to show the loader).
final GlobalKey<State> _LoaderDialog = new GlobalKey<State>();
// Show
LoaderDialog.showLoadingDialog(context, _LoaderDialog);
// Hide
Navigator.of(_LoaderDialog.currentContext,rootNavigator: true).pop();
I cannot validate Steps individually. I can validate fields in a Stepper, problem is that I want to validate fields before going to the next step.
Creating multiple forms is not a good option. I tried that and it is not practical. Is there any way to either:
Detect the current step and validate fields only inside that step
A simple way to validate step by step, not on submit
Use List<GlobalKey<FormState>> to control each step's validation
When user click continue do formKeys[currStep].currentState.validate()
You can copy paste run full code below
code snippet
List<GlobalKey<FormState>> formKeys = [GlobalKey<FormState>(), GlobalKey<FormState>(), GlobalKey<FormState>(), GlobalKey<FormState>()];
...
return Container(
child: Form(
key: _formKey,
child: ListView(children: <Widget>[
Stepper(
steps: steps,
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if(formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
});
},
...
List<Step> steps = [
Step(
title: const Text('Name'),
//subtitle: const Text('Enter your name'),
isActive: true,
//state: StepState.error,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: Column(
children: <Widget>[
TextFormField(
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String value) {
data.name = value;
},
maxLines: 1,
//initialValue: 'Aseem Wangoo',
validator: (value) {
if (value.isEmpty || value.length < 1) {
return 'Please enter name';
}
},
decoration: InputDecoration(
labelText: 'Enter your name',
hintText: 'Enter a name',
//filled: true,
icon: const Icon(Icons.person),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp( MyApp());
}
List<GlobalKey<FormState>> formKeys = [GlobalKey<FormState>(), GlobalKey<FormState>(), GlobalKey<FormState>(), GlobalKey<FormState>()];
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppScreenMode();
}
}
class MyData {
String name = '';
String phone = '';
String email = '';
String age = '';
}
class MyAppScreenMode extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.lightGreen,
),
home: Scaffold(
appBar: AppBar(
title: Text('Steppers'),
),
body: StepperBody(),
));
}
}
class StepperBody extends StatefulWidget {
#override
_StepperBodyState createState() => _StepperBodyState();
}
class _StepperBodyState extends State<StepperBody> {
int currStep = 0;
static var _focusNode = FocusNode();
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
static MyData data = MyData();
#override
void initState() {
super.initState();
_focusNode.addListener(() {
setState(() {});
print('Has focus: $_focusNode.hasFocus');
});
}
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
List<Step> steps = [
Step(
title: const Text('Name'),
//subtitle: const Text('Enter your name'),
isActive: true,
//state: StepState.error,
state: StepState.indexed,
content: Form(
key: formKeys[0],
child: Column(
children: <Widget>[
TextFormField(
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
onSaved: (String value) {
data.name = value;
},
maxLines: 1,
//initialValue: 'Aseem Wangoo',
validator: (value) {
if (value.isEmpty || value.length < 1) {
return 'Please enter name';
}
},
decoration: InputDecoration(
labelText: 'Enter your name',
hintText: 'Enter a name',
//filled: true,
icon: const Icon(Icons.person),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
Step(
title: const Text('Phone'),
//subtitle: const Text('Subtitle'),
isActive: true,
//state: StepState.editing,
state: StepState.indexed,
content: Form(
key: formKeys[1],
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.phone,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length < 10) {
return 'Please enter valid number';
}
},
onSaved: (String value) {
data.phone = value;
},
maxLines: 1,
decoration: InputDecoration(
labelText: 'Enter your number',
hintText: 'Enter a number',
icon: const Icon(Icons.phone),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
Step(
title: const Text('Email'),
// subtitle: const Text('Subtitle'),
isActive: true,
state: StepState.indexed,
// state: StepState.disabled,
content: Form(
key: formKeys[2],
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.emailAddress,
autocorrect: false,
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please enter valid email';
}
},
onSaved: (String value) {
data.email = value;
},
maxLines: 1,
decoration: InputDecoration(
labelText: 'Enter your email',
hintText: 'Enter a email address',
icon: const Icon(Icons.email),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
Step(
title: const Text('Age'),
// subtitle: const Text('Subtitle'),
isActive: true,
state: StepState.indexed,
content: Form(
key: formKeys[3],
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.number,
autocorrect: false,
validator: (value) {
if (value.isEmpty || value.length > 2) {
return 'Please enter valid age';
}
},
maxLines: 1,
onSaved: (String value) {
data.age = value;
},
decoration: InputDecoration(
labelText: 'Enter your age',
hintText: 'Enter age',
icon: const Icon(Icons.explicit),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid)),
),
],
),
)),
// Step(
// title: const Text('Fifth Step'),
// subtitle: const Text('Subtitle'),
// isActive: true,
// state: StepState.complete,
// content: const Text('Enjoy Step Fifth'))
];
#override
Widget build(BuildContext context) {
void showSnackBarMessage(String message,
[MaterialColor color = Colors.red]) {
Scaffold
.of(context)
.showSnackBar( SnackBar(content: Text(message)));
}
void _submitDetails() {
final FormState formState = _formKey.currentState;
if (!formState.validate()) {
showSnackBarMessage('Please enter correct data');
} else {
formState.save();
print("Name: ${data.name}");
print("Phone: ${data.phone}");
print("Email: ${data.email}");
print("Age: ${data.age}");
showDialog(
context: context,
child: AlertDialog(
title: Text("Details"),
//content: Text("Hello World"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text("Name : " + data.name),
Text("Phone : " + data.phone),
Text("Email : " + data.email),
Text("Age : " + data.age),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
));
}
}
return Container(
child: ListView(children: <Widget>[
Stepper(
steps: steps,
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if(formKeys[currStep].currentState.validate()) {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
currStep = 0;
}
}
// else {
// Scaffold
// .of(context)
// .showSnackBar( SnackBar(content: Text('$currStep')));
// if (currStep == 1) {
// print('First Step');
// print('object' + FocusScope.of(context).toStringDeep());
// }
// }
});
},
onStepCancel: () {
setState(() {
if (currStep > 0) {
currStep = currStep - 1;
} else {
currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
RaisedButton(
child: Text(
'Save details',
style: TextStyle(color: Colors.white),
),
onPressed: _submitDetails,
color: Colors.blue,
),
]));
}
}