I have a question about validation. My widget field validation is become true before checked. when I am just open this page validation is automatically becomes true.
I want that validation after user input. but this validation is becoming true before the user entering something inside from the field. so can anyone help me? your help will be appreciated.
Here is the code I've tried.
class BspSignupPage extends StatefulWidget {
static const String routeName = "/bspSignup";
#override
_BspSignupPageState createState() => _BspSignupPageState();
}
class _BspSignupPageState extends State<BspSignupPage>
with AfterLayoutMixin<BspSignupPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
// final TextEditingController _bspPhone = TextEditingController();
final MaskedTextController _bspPhone =
new MaskedTextController(mask: '(000)-000-0000');
final TextEditingController _bspBusinessName = TextEditingController();
final TextEditingController _bspBusinessLegalAddress =
TextEditingController();
final TextEditingController _bspBusinessLicense = TextEditingController();
final TextEditingController _bspLicenseAuthority = TextEditingController();
final TextEditingController _bspEstYear = TextEditingController();
final TextEditingController _bspNumberOfEmployee = TextEditingController();
final TextEditingController _bspBusinessDetailsComment =
TextEditingController();
final TextEditingController _countryCodeController =
new TextEditingController();
BSPSignupRepository _bspSignupRepository = new BSPSignupRepository();
bool bspcheck = false;
BspSignupCommonModel model = BspSignupCommonModel();
int radioValue = -1;
String _alternatephone;
String _businessname;
bool addressenabled = false;
List<dynamic> _type = <dynamic>[];
Map<String, dynamic> _typeValue;
String _establishyear;
String _numberofemployee;
LocationResult _pickedLocation;
DateTime selectedDate = DateTime.now();
bool flexibletime = false;
DateTime date;
TimeOfDay time;
Map<String, dynamic> bspsignupdata = new Map<String, dynamic>();
#override
void initState() {
super.initState();
print(model);
_bspNumberOfEmployee.text = "1";
_bspSignupRepository.getBSTypes().then((businessTypeResponse) {
print('businessTypeResponse');
print(businessTypeResponse);
if (businessTypeResponse['error'] != null) {
} else {
setState(() {
_type = businessTypeResponse['data']['businessTypes'];
});
}
});
setState(() {
date = new DateTime.now().add(new Duration(hours: 1));
time = new TimeOfDay.fromDateTime(date);
});
}
#override
void afterFirstLayout(BuildContext context) {
model = ModalRoute.of(context).settings.arguments;
if (model == null) {
model = new BspSignupCommonModel();
} else {
print('model for edit');
_setExistingDetails(model);
}
}
void _setExistingDetails(bspModel) {
_bspBusinessName.text = bspModel.businessLegalName;
_bspPhone.text = model.businessPhoneNumber;
_bspEstYear.text = model.businessYear;
_bspNumberOfEmployee.text = model.numberofEmployees;
_bspBusinessLegalAddress.text = model.businessLegalAddress;
_typeValue = model.businessTypes;
}
Widget _buildlegalbusinessname() {
return new TudoTextWidget(
controller: _bspBusinessName,
textCapitalization: TextCapitalization.sentences,
prefixIcon: Icon(Icons.business),
labelText: AppConstantsValue.appConst['bspSignup']['legalbusinessname']
['translation'],
hintText: AppConstantsValue.appConst['bspSignup']['legalbusinessname']
['translation'],
validator: (val) =>
Validators.validateRequired(val, "Business legal name"),
onSaved: (val) {
_businessname = val;
bspsignupdata['businessname'] = _businessname;
},
);
}
Widget _buildalternatephone() {
return Row(
children: <Widget>[
new Expanded(
child: new TudoTextWidget(
controller: _countryCodeController,
enabled: false,
prefixIcon: Icon(FontAwesomeIcons.globe),
labelText: "code",
hintText: "Country Code",
),
flex: 2,
),
new SizedBox(
width: 10.0,
),
new Expanded(
child: new TudoNumberWidget(
controller: _bspPhone,
validator: Validators().validateMobile,
labelText: AppConstantsValue.appConst['bspSignup']['alternatephone']
['translation'],
hintText: AppConstantsValue.appConst['bspSignup']['alternatephone']
['translation'],
prefixIcon: Icon(Icons.phone),
onSaved: (val) {
_alternatephone = val;
bspsignupdata['alternatephone'] = _alternatephone;
},
),
flex: 5,
),
],
);
}
Widget _buildestablishedyear() {
return new TudoNumberWidget(
controller: _bspEstYear,
prefixIcon: Icon(FontAwesomeIcons.calendar),
labelText: AppConstantsValue.appConst['bspSignup']['establishedyear']
['translation'],
hintText: AppConstantsValue.appConst['bspSignup']['establishedyear']
['translation'],
validator: Validators().validateestablishedyear,
maxLength: 4,
onSaved: (val) {
_establishyear = val.trim();
bspsignupdata['establishyear'] = _establishyear;
},
);
}
Widget _buildnumberofemployees() {
return new TudoNumberWidget(
controller: _bspNumberOfEmployee,
prefixIcon: Icon(Icons.control_point_duplicate),
labelText: AppConstantsValue.appConst['bspSignup']['numberofemployees']
['translation'],
hintText: AppConstantsValue.appConst['bspSignup']['numberofemployees']
['translation'],
validator: Validators().validatenumberofemployee,
onSaved: (val) {
_numberofemployee = val.trim();
bspsignupdata['numberofemployes'] = _numberofemployee;
},
);
}
Widget _buildbusinesslegaladdress() {
return Row(
children: <Widget>[
new Expanded(
child: new TudoTextWidget(
prefixIcon: Icon(Icons.business),
labelText: AppConstantsValue.appConst['bspSignup']
['businesslegaladdress']['translation'],
hintText: AppConstantsValue.appConst['bspSignup']
['businesslegaladdress']['translation'],
controller: _bspBusinessLegalAddress,
enabled: addressenabled,
validator: (val) =>
Validators.validateRequired(val, "Business legal name"),
),
flex: 5,
),
new SizedBox(
width: 10.0,
),
new Expanded(
child: new FloatingActionButton(
backgroundColor: colorStyles['primary'],
child: Icon(
FontAwesomeIcons.globe,
color: Colors.white,
),
elevation: 0,
onPressed: () async {
LocationResult result = await LocationPicker.pickLocation(
context,
"AIzaSyDZZeGlIGUIPs4o8ahJE_yq6pJv3GhbKQ8",
);
print("result = $result");
setState(() {
_pickedLocation = result;
addressenabled = !addressenabled;
});
// setState(() => _pickedLocation = result);
_bspBusinessLegalAddress.text = _pickedLocation.address;
model.businessGeoLocation = new BusinessGeoLocation(
lat: _pickedLocation.latLng.latitude.toString(),
lng: _pickedLocation.latLng.longitude.toString(),
);
},
),
flex: 2,
),
],
);
}
Widget _buildbusinesstype() {
return FormBuilder(
autovalidate: true,
child: FormBuilderCustomField(
attribute: "Business type",
validators: [FormBuilderValidators.required()],
formField: FormField(
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_identity),
labelText: _type == []
? 'Select Personal Identification type'
: 'Business type',
hintText: "Select Personal Identification type",
errorText: field.errorText,
),
isEmpty: _typeValue == [],
child: new DropdownButtonHideUnderline(
child: new DropdownButton(
// isExpanded: true,
hint: Text("Select Personal Identification type"),
value: _typeValue,
isDense: true,
onChanged: (dynamic newValue) {
print('newValue');
print(newValue);
setState(() {
_typeValue = newValue;
field.didChange(newValue);
});
},
items: _type.map(
(dynamic value) {
return new DropdownMenuItem(
value: value,
child: new Text(value['name']),
);
},
).toList(),
),
),
);
},
)),
);
}
Widget _buildlegalbusinesscheck() {
return TudoConditionWidget(
text: AppConstantsValue.appConst['bspSignup']['legalbusinesscheck']
['translation'],
errortext: AppConstantsValue.appConst['bspSignup']['errortext']
['translation'],
);
}
Widget content(BuildContext context, BspSignupViewModel bspSignupVm) {
final appBar = AppBar(
title: Text("BSP Signup"),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
NavigationHelper.navigatetoBack(context);
},
),
centerTitle: true,
);
final bottomNavigationBar = Container(
color: Colors.transparent,
height: 56,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(Icons.close),
label: Text('Clear'),
color: Colors.redAccent,
textColor: Colors.black,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
_formKey.currentState.reset();
_bspPhone.clear();
_bspBusinessName.clear();
_bspBusinessLicense.clear();
_bspLicenseAuthority.clear();
_bspEstYear.clear();
_bspNumberOfEmployee.clear();
_bspBusinessDetailsComment.clear();
_bspBusinessLegalAddress.clear();
},
),
new FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Next'),
color: colorStyles["primary"],
textColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
model.businessLegalName = _bspBusinessName.text;
model.businessPhoneNumber = _bspPhone.text;
model.businessYear = _bspEstYear.text;
model.numberofEmployees = _bspNumberOfEmployee.text;
model.businessType = _typeValue['id'];
model.businessLegalAddress = _bspBusinessLegalAddress.text;
model.businessTypes = _typeValue;
print('model');
print(model.licensed);
if (_typeValue['name'].toLowerCase() ==
"Licensed / Registered".toLowerCase()) {
model.isLicensed = true;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BspLicensedSignupPage(
bspSignupCommonModel: model,
),
),
);
} else {
model.isLicensed = false;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BspUnlicensedSignupPage(
bspSignupCommonModel: model,
),
),
);
}
}
},
),
],
),
);
return Scaffold(
appBar: appBar,
bottomNavigationBar: bottomNavigationBar,
body: Container(
height: double.infinity,
width: double.infinity,
child: Form(
autovalidate: true,
key: _formKey,
child: Stack(
children: <Widget>[
// Background(),
SingleChildScrollView(
padding: const EdgeInsets.all(30.0),
child: new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildlegalbusinessname(),
_buildalternatephone(),
_buildestablishedyear(),
_buildnumberofemployees(),
SizedBox(
height: 5,
),
_buildbusinesslegaladdress(),
_buildbusinesstype(),
_buildlegalbusinesscheck(),
],
),
),
),
],
),
),
),
);
}
#override
Widget build(BuildContext context) {
return new StoreConnector<AppState, BspSignupViewModel>(
converter: (Store<AppState> store) => BspSignupViewModel.fromStore(store),
onInit: (Store<AppState> store) {
_countryCodeController.text =
store.state.auth.loginUser.user.country.isdCode;
},
builder: (BuildContext context, BspSignupViewModel bspSignupVm) =>
content(context, bspSignupVm),
);
}
}
your widget field validation is become true before checked becuase you have given static flag true to "autovalidate" to solve this issue you have to manage flag variable for that
Example:-
bool _autoValidate = false;
Form(
key: _formKey,
autovalidate: _autoValidate,
child: Container(child:Text("")));
And change flag value when first time validating form
void _buttonClicked(BuildContext context) {
setState(() {
_autoValidate = true;
});
}
Update:-
autovalidate is deprecated from Flutter v1.19
Replace autovalidate with autovalidateMode.autovalidateMode can have one of the below 3 values:
autovalidateMode: AutovalidateMode.disabled: No auto validation will occur.
autovalidateMode: AutovalidateMode.always: Used to auto-validate FormField even without user interaction.
autovalidateMode: AutovalidateMode.onUserInteraction: Used to auto-validate FormField only after each user interaction.
Related
Steps to Reproduce
Here is the dartpad link go to it.
Enter any values to the Fields calculate the answer.
Add 0. to the start any Field
Expected results: validator should return 0.xyz
Actual results: validator returns 0xyz
Work around found: using onSaved solves this
Can anyone tell me why is it happening or is it bug in flutter then I will a new issue in the flutter repo
I'm printing the value coming from validator and in onChanged parsing string value to int.
Edit
when input 23 and then inert 0. , this line amount = int.parse(val); execute and stop and then click calculate button, so amount is 23 and value's runtimeType is String 023
TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
print("amount $amount");
print(" ${value.runtimeType}");
print("validator amount value $value ");
if (value.isEmpty) {
return "Enter some amount";
} else if (double.parse(value).toInt() <= 0) {
return "Amount should be greater than 0";
}
return null;
},
onChanged: (val){
print("val1 $val");
amount = int.parse(val);
print("amount $amount");
}
You can copy paste run full code below
The reason why validator not return 0.xyz
Because onChanged executed before validator
So validator receive truncated value by int.parse(value)
If you remove amount = int.parse(value); validator will get correct value but
this condition if (int.parse(value) <= 0) will get Invalid radix-10 number
You need to change to if (double.parse(value).toInt() <= 0)
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
buttonTheme: ButtonThemeData(
buttonColor: Colors.purple.shade400,
),
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: BillSpitApp(),
);
}
}
class BillSpitApp extends StatefulWidget {
BillSpitApp({Key key}) : super(key: key);
#override
_BillSpitAppState createState() => _BillSpitAppState();
}
class _BillSpitAppState extends State<BillSpitApp> {
int amount;
int numOfPersons;
double splitAmount;
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Bill split app"),
),
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
splitAmount == null
? "Fill the details and click on calculate to get your bill split"
: "Bill split is ${splitAmount.toStringAsFixed(2)}",
style: TextStyle(
fontSize: 25,
),
textAlign: TextAlign.center,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 15.0),
child: TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
print("validator amount value $value");
if (value.isEmpty) {
return "Enter some amount";
} else if (double.parse(value).toInt() <= 0) {
return "Amount should be greater than 0";
}
return null;
},
onSaved: (value) {
print("onSaved amount value $value");
amount = int.parse(value);
//int.parse(value);
},
decoration: InputDecoration(
labelText: "Amount",
hintText: "1000",
border: OutlineInputBorder(),
),
),
),
TextFormField(
validator: (value) {
print("person value $value");
if (value.isEmpty) {
return "Enter number of persons";
} else if (double.parse(value).toInt() <= 0) {
return "Number should be greater than 0";
}
return null;
},
onSaved: (value) {
print("onsave numOfPersons $value");
numOfPersons = int.parse(value);
},
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: "Number of persons",
hintText: "5",
border: OutlineInputBorder(),
),
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: RaisedButton(
child: Text(
"Calculate",
style: TextStyle(color: Colors.white),
),
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print("calculate $amount");
print("calculate $numOfPersons");
setState(() {
splitAmount = amount / numOfPersons;
});
}
},
),
),
],
),
),
),
);
}
}
It is not flutter bug however when you take amount as integer any value starts with 0, flutter takes it as 0.
if (value.isEmpty) {
return "Enter some amount";
} else if (double.parse(value) <= 0) {
return "Amount should be greater than 0";
}
return null;
and
onChanged: (value) {
amount = double.parse(value);
},
I am trying to upload images for some days and it's not working so please if you have a working code put it as an answer or just solve the code
Here is the code
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:mazadi/Models/ImageUpload.dart';
import 'package:multi_image_picker/multi_image_picker.dart';
class AddAd3 extends StatefulWidget {
AddAd3({
Key key,
}) : super(key: key);
#override
_AddAd3State createState() => _AddAd3State();
}
class _AddAd3State extends State<AddAd3> {
bool _isUploading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(12.0),
child: ListView(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
width: 100,
height: 100,
child: RaisedButton(
onPressed: () {
getImage();
},
color: Colors.white,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(7.0)),
child: SizedBox(
width: 90,
height: 90,
child: Center(
child: Icon(
Icons.add,
color: Colors.deepOrange,
size: 30.0,
),
),
),
),
),
],
),
SizedBox(
height: 40,
),
SizedBox(
width: 500,
height: 500,
child: _isUploading == true
? FutureBuilder(
future: uploadImage(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return new Text('${snapshot.error}');
else
return createListView(context, snapshot);
}
},
)
: Text(""),
),
],
),
));
}
Future getImage() async {
files.clear();
List<Asset> resultList = List<Asset>();
resultList = await MultiImagePicker.pickImages(
maxImages: 10,
enableCamera: false,
);
for (var asset in resultList) {
int MAX_WIDTH = 500; //keep ratio
int height = ((500 * asset.originalHeight) / asset.originalWidth).round();
ByteData byteData =
await asset.getThumbByteData(MAX_WIDTH, height, quality: 80);
if (byteData != null) {
List<int> imageData = byteData.buffer.asUint8List();
MultipartFile u = MultipartFile.fromBytes(
imageData,
filename: asset.name,
);
files.add(u);
}
}
setState(() {
_isUploading = true;
});
}
List<MultipartFile> files = new List<MultipartFile>();
Future<List<String>> uploadImage() async {
FormData formData = new FormData.fromMap({"thumb": files});
Dio dio = new Dio();
var response = await dio.post(
"https://mazadyy.com/index.php?route=api/customer_product/uploadImages",
data: formData);
UploadImage image = UploadImage.fromJson(response.data);
return image.images;
}
Widget createListView(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text("error createListView");
}
if (!snapshot.hasData) {
return Text("");
}
List<String> values = snapshot.data;
return new ListView.builder(
shrinkWrap: true,
itemCount: values.length,
itemBuilder: (BuildContext context, int index) {
return new Column(
children: <Widget>[
Image.network(
values[index],
width: 300,
height: 100,
),
SizedBox(
height: 40,
),
],
);
},
);
}
}
and here it the model
class UploadImage {
List<String> images;
UploadImage({this.images});
factory UploadImage.fromJson(Map<String, dynamic> json) {
return UploadImage(images: parseImage(json['images']));
}
static List<String> parseImage(json) {
return new List<String>.from(json);
}
}
the exception that I get is
type String is not a subtype of 'Map<String, dynamic>'
so if you solved the error I will really appreciate it and give him 50 reputation as a reward because
I saw many struggle with the same problem
any help will be appreciated whatever it's
if (images.isEmpty || images[0] != null) {
for (int i = 0; i < images.length; i++) {
ByteData byteData = await images[i].getByteData();
List<int> imageData = byteData.buffer.asUint8List();
http.MultipartFile multipartFile =
http.MultipartFile.fromBytes('image', imageData,
filename: images[i].name,
contentType: MediaType('image', 'jpg'));
imagestoEdit.add(multipartFile);
print(imagestoEdit.length);
}
}
Dio.post(url,formdata:{images:imagestoEdit})
normal image
image after entering the mobile number
See in this image when a user clicks on the login button the login button should disappear and a text field will be there followed by a submit button.
I have the text field appearing on click of the login button, however I don't know how to disappear that login button once it is pressed.
import 'dart:async';
import 'dart:ffi';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../widgets/landing_page.dart';
import '../screens/register.dart';
import 'package:google_sign_in/google_sign_in.dart';
import '../widgets/google_sign_in_btn.dart';
import '../widgets/reactive_refresh_indicator.dart';
// Each item on AuthStatus represents quite literally the status of the UI.
// On SOCIAL_AUTH only the GoogleSignInButton will be visible.
enum AuthStatus { SOCIAL_AUTH }
class AuthScreen extends StatefulWidget {
#override
_AuthScreenState createState() => _AuthScreenState();
}
// On _AuthScreenState we start by defining the tag that will be used for our logger, then the default status as SOCIAL_AUTH, which means we need to do Google's sign in and the GoogleSignInButton will be visible and interactive.
class _AuthScreenState extends State<AuthScreen> {
String phoneNo;
String smsCode;
String verificationId;
bool _smsCodeDisabled = true;
bool isThere;
bool isPresent;
bool _canShowButton = false;
final db = Firestore.instance;
Firestore.instance.collection('transcriber_user_registeration').where('mobileno', isEqualTo: phoneNo)
// .snapshots().listen(
// (data) { print("Inside phone number check : $data"); });
// // return phoneNumberCheck(phoneNo);
// QuerySnapshot result =
// await Firestore.instance.collection('transcriber_user_registeration').getDocuments();
// var list = result.documents;
// print("Before data loop");
// list.forEach((data) => print(data));
// print("After data loop");
Future<void> phoneNumberCheck(String phoneNo) async {
print("Start of the function");
//bool registerState = false;
//bool isPresent = false;
Firestore.instance
.collection("transcriber_user_registeration")
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f) async {
if (isPresent = ('${f.data['mobileno']}' == phoneNo)) {
print(isPresent);
final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verId) {
this.verificationId = verId;
};
final PhoneCodeSent smsCodeSent =
(String verId, [int forceCodeResend]) {
this.verificationId = verId;
print("im in sms code dialog");
// smsCodeDialog(context).then((value) {
// print('Signed in');
// });
setState(() {
this._smsCodeDisabled = false;
});
};
final PhoneVerificationCompleted verifySuccess =
(AuthCredential user) {
print("verified");
};
final PhoneVerificationFailed verifyFailed =
(AuthException exception) {
print('${exception.message}');
};
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: this.phoneNo,
codeAutoRetrievalTimeout: autoRetrieve,
codeSent: smsCodeSent,
timeout: const Duration(seconds: 5),
verificationCompleted: verifySuccess,
verificationFailed: verifyFailed,
);
}
// else {
// _showMessage();
// }
});
});
//print("End of the function $isPresent");
}
Future<void> verifyPhone() async {
// final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verId) {
// this.verificationId = verId;
// };
var tmp1 = phoneNo.toString();
print('ref stsmt starts $tmp1');
await phoneNumberCheck(phoneNo);
print("After execution of the function $isPresent");
print('bvnnn');
}
Future<bool> smsCodeDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return new AlertDialog(
title: Text('Enter sms code'),
content: TextField(onChanged: (value) {
this.smsCode = value;
}),
contentPadding: EdgeInsets.all(10.0),
actions: <Widget>[
new FlatButton(
child: Text('Login'),
onPressed: () async {
//await signIn();
await FirebaseAuth.instance.currentUser().then((user) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => LandingPageApp()));
});
})
],
);
});
}
signIn() {
print("came to sign in page");
final AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode,
);
FirebaseAuth.instance.signInWithCredential(credential).then((user) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LandingPageApp()));
}).catchError((e) {
print(e);
});
}
void hideWidget() {
setState(() {
_canShowButton != _canShowButton;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Flexible(
flex: 1,
child: new Container(
//color: Colors.white,
height: 200.0,
width: 400.0,
decoration: new BoxDecoration(
image: DecorationImage(
image: new AssetImage('assets/images/download.png'),
),
),
),
),
SizedBox(height: 20.0),
Padding(
padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 20.0),
child: TextFormField(
decoration:
InputDecoration(hintText: 'Enter your Phone number'),
keyboardType: TextInputType.phone,
onChanged: (value) {
this.phoneNo = "+91$value";
},
validator: validateMobile),
),
SizedBox(height: 10.0),
Visibility(
visible: _canShowButton,
child: RaisedButton(
child: Text('Login'),
textColor: Colors.white,
elevation: 7.0,
color: Colors.blue,
onPressed: () async {
bool _canShowButton = true;
await verifyPhone();
setState(() {
_canShowButton = !_canShowButton;
});
hideWidget();
//_number();
},
),
),
_smsCodeDisabled
? SizedBox(height: 10.0)
: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(
horizontal: 20.0, vertical: 16.0),
child: TextFormField(
decoration:
InputDecoration(hintText: 'Enter OTP'),
keyboardType: TextInputType.number,
onChanged: (value) {
this.smsCode = value;
},
validator: validateOtp),
),
SizedBox(height: 10.0),
RaisedButton(
onPressed: () async {
await signIn();
FirebaseAuth.instance.currentUser().then((user) {
print(["user", user]);
if (user != null) {
print(user.uid);
// Navigator.of(context).pop();
//// Navigator.of(context).pushReplacementNamed('/homePage');
// Navigator.of(context).push(
// MaterialPageRoute<Null>(
// builder: (BuildContext context) {
// return new LandingPageApp();
// }));
} else {
print("user is null");
Navigator.of(context).pop();
signIn();
}
});
},
child: Text('Submit'),
textColor: Colors.white,
elevation: 7.0,
color: Colors.blue,
),
],
),
SizedBox(
height: 20.0,
),
Column(
children: <Widget>[
Row(children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(
vertical: 16.0, horizontal: 20.0),
child: Text(
'Not a Registered User?',
style: TextStyle(
fontSize: 16,
),
),
),
MaterialButton(
child: Text(
'Register',
style: TextStyle(
color: Colors.black,
),
),
//color: Colors.blue,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Register()));
},
),
]),
],
),
],
),
));
}
}
String validateMobile(String value) {
//Indian Mobile numbers are of 10 digits only.
if (value.length != 10)
return 'Mobile number must be of 10 digits';
else
return null;
}
String validateOtp(String value) {
//Otp needs to be of 6 digits
if (value.length != 6)
return 'OTP must be of 6 digits';
else
return null;
}
Please try this
bool _canShowButton = true;
void hideWidget() {
setState(() {
_canShowButton = !_canShowButton;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test Screen'),
),
body: Container(
padding: const EdgeInsets.all(8),
child: Column(
children: <Widget>[
Flexible(
flex: 1,
child: Container(
//color: Colors.white,
height: 200.0,
width: 400.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('https://picsum.photos/250?image=10'),
),
),
),
),
SizedBox(height: 20.0),
///if the show button is false
!_canShowButton
? const SizedBox.shrink()
: RaisedButton(
child: Text('Login'),
textColor: Colors.white,
elevation: 7.0,
color: Colors.blue,
onPressed: () {
hideWidget();
//_number();
},
),
],
)),
);
}
In your build method, you already have a boolean _smsCodeDisabled to identify whether the otp field need to show or not. You can use the same boolean to hide the login field and button. The logic should be something like:
#override
Widget build(BuildContext context) {
return _smsCodeDisabled ? _getLoginWidget() : _getOtpWidget();
}
Widget _getLoginWidget() {
// Return Login field and button
}
Widget _getOtpWidget() {
// Return otp field and button
}
Or If you need to only hide the login button, use the following logic:
#override
Widget build(BuildContext context) {
return Scaffold(
// other code
// Login button logic
_smsCodeDisabled ? RaisedButton(...) : Container();
);
}
Below is the code I have tried but it completely fails. If I Remove the WhitelistingTextInputFormatter, I get the Number keyboard and I can insert numbers and periods. but the number of period I can use is more than one, which I need to limit at just one. how to do this?
TextField(
controller: _weightCtr,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
BlacklistingTextInputFormatter(new RegExp('[\\-|\\ ]')),
WhitelistingTextInputFormatter(new RegExp('^\d+[\.\,]\d+\$')),
],
decoration: InputDecoration(
hintText: "Please enter a valid weight for this trip",
),
style: Theme.of(context).textTheme.title.copyWith(
fontWeight: FontWeight.w300,
fontSize: 14,
),
),
You can copy paste run full code below
You can extend TextInputFormatter and remove extra dot
In working demo you can see when extra dot will not show on screen
code snippet
class NumberRemoveExtraDotFormatter extends TextInputFormatter {
NumberRemoveExtraDotFormatter({this.decimalRange = 3})
if (nValue.split('.').length > 2) {
List<String> split = nValue.split('.');
nValue = split[0] + '.' + split[1];
}
...
TextField(
controller: _weightCtr,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
NumberRemoveExtraDotFormatter()
//BlacklistingTextInputFormatter(new RegExp('[\\-|\\ ]')),
//WhitelistingTextInputFormatter(new RegExp('^\d+[\.\,]\d+\$')),
],
decoration: InputDecoration(
hintText: "Please enter a valid weight for this trip",
),
style: Theme.of(context).textTheme.title.copyWith(
fontWeight: FontWeight.w300,
fontSize: 14,
),
),
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:math' as math;
class NumberRemoveExtraDotFormatter extends TextInputFormatter {
NumberRemoveExtraDotFormatter({this.decimalRange = 3})
: assert(decimalRange == null || decimalRange > 0);
final int decimalRange;
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
String nValue = newValue.text;
TextSelection nSelection = newValue.selection;
Pattern p = RegExp(r'(\d+\.?)|(\.?\d+)|(\.?)');
nValue = p
.allMatches(nValue)
.map<String>((Match match) => match.group(0))
.join();
if (nValue.startsWith('.')) {
nValue = '0.';
} else if (nValue.contains('.')) {
if (nValue.substring(nValue.indexOf('.') + 1).length > decimalRange) {
nValue = oldValue.text;
} else {
if (nValue.split('.').length > 2) {
List<String> split = nValue.split('.');
nValue = split[0] + '.' + split[1];
}
}
}
nSelection = newValue.selection.copyWith(
baseOffset: math.min(nValue.length, nValue.length + 1),
extentOffset: math.min(nValue.length, nValue.length + 1),
);
return TextEditingValue(
text: nValue, selection: nSelection, composing: TextRange.empty);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
TextEditingController _weightCtr = TextEditingController();
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _weightCtr,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
NumberRemoveExtraDotFormatter()
//BlacklistingTextInputFormatter(new RegExp('[\\-|\\ ]')),
//WhitelistingTextInputFormatter(new RegExp('^\d+[\.\,]\d+\$')),
],
decoration: InputDecoration(
hintText: "Please enter a valid weight for this trip",
),
style: Theme.of(context).textTheme.title.copyWith(
fontWeight: FontWeight.w300,
fontSize: 14,
),
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I tried to find how to select and upload multiple images in flutter but most of the plugins are not working or I did not understand them well. I found little application but it selects and upload only one picture. How to change this code that user can select and upload multiple pictures or is there any other alternatives. Please write in details, i am freshman in coding. Thanks in advance.
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:mime/mime.dart';
import 'dart:convert';
import 'package:http_parser/http_parser.dart';
import 'package:toast/toast.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Upload Demo',
theme: ThemeData(primarySwatch: Colors.pink),
home: ImageInput());
}
}
class ImageInput extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ImageInput();
}
}
class _ImageInput extends State<ImageInput> {
// To store the file provided by the image_picker
File _imageFile;
// To track the file uploading state
bool _isUploading = false;
String baseUrl = 'http://YOUR_IPV4_ADDRESS/flutterdemoapi/api.php';
void _getImage(BuildContext context, ImageSource source) async {
File image = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = image;
});
// Closes the bottom sheet
Navigator.pop(context);
}
Future<Map<String, dynamic>> _uploadImage(File image) async {
setState(() {
_isUploading = true;
});
// Find the mime type of the selected file by looking at the header bytes of the file
final mimeTypeData =
lookupMimeType(image.path, headerBytes: [0xFF, 0xD8]).split('/');
// Intilize the multipart request
final imageUploadRequest =
http.MultipartRequest('POST', Uri.parse(baseUrl));
// Attach the file in the request
final file = await http.MultipartFile.fromPath('image', image.path,
contentType: MediaType(mimeTypeData[0], mimeTypeData[1]));
// Explicitly pass the extension of the image with request body
// Since image_picker has some bugs due which it mixes up
// image extension with file name like this filenamejpge
// Which creates some problem at the server side to manage
// or verify the file extension
imageUploadRequest.fields['ext'] = mimeTypeData[1];
imageUploadRequest.files.add(file);
try {
final streamedResponse = await imageUploadRequest.send();
final response = await http.Response.fromStream(streamedResponse);
if (response.statusCode != 200) {
return null;
}
final Map<String, dynamic> responseData = json.decode(response.body);
_resetState();
return responseData;
} catch (e) {
print(e);
return null;
}
}
void _startUploading() async {
final Map<String, dynamic> response = await _uploadImage(_imageFile);
print(response);
// Check if any error occured
if (response == null || response.containsKey("error")) {
Toast.show("Image Upload Failed!!!", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
} else {
Toast.show("Image Uploaded Successfully!!!", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
}
}
void _resetState() {
setState(() {
_isUploading = false;
_imageFile = null;
});
}
void _openImagePickerModal(BuildContext context) {
final flatButtonColor = Theme.of(context).primaryColor;
print('Image Picker Modal Called');
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 150.0,
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Text(
'Pick an image',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(
height: 10.0,
),
FlatButton(
textColor: flatButtonColor,
child: Text('Use Camera'),
onPressed: () {
_getImage(context, ImageSource.camera);
},
),
FlatButton(
textColor: flatButtonColor,
child: Text('Use Gallery'),
onPressed: () {
_getImage(context, ImageSource.gallery);
},
),
],
),
);
});
}
Widget _buildUploadBtn() {
Widget btnWidget = Container();
if (_isUploading) {
// File is being uploaded then show a progress indicator
btnWidget = Container(
margin: EdgeInsets.only(top: 10.0),
child: CircularProgressIndicator());
} else if (!_isUploading && _imageFile != null) {
// If image is picked by the user then show a upload btn
btnWidget = Container(
margin: EdgeInsets.only(top: 10.0),
child: RaisedButton(
child: Text('Upload'),
onPressed: () {
_startUploading();
},
color: Colors.pinkAccent,
textColor: Colors.white,
),
);
}
return btnWidget;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Upload Demo'),
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 40.0, left: 10.0, right: 10.0),
child: OutlineButton(
onPressed: () => _openImagePickerModal(context),
borderSide:
BorderSide(color: Theme.of(context).accentColor, width: 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.camera_alt),
SizedBox(
width: 5.0,
),
Text('Add Image'),
],
),
),
),
_imageFile == null
? Text('Please pick an image')
: Image.file(
_imageFile,
fit: BoxFit.cover,
height: 300.0,
alignment: Alignment.topCenter,
width: MediaQuery.of(context).size.width,
),
_buildUploadBtn(),
],
),
);
}
}
I used that package:
dependencies:
multi_image_picker: ^4.6.7
Ex:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:multi_image_picker/multi_image_picker.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Asset> images = List<Asset>();
String _error;
#override
void initState() {
super.initState();
}
Widget buildGridView() {
if (images != null)
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
else
return Container(color: Colors.white);
}
Future<void> loadAssets() async {
setState(() {
images = List<Asset>();
});
List<Asset> resultList;
String error;
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
);
} on Exception catch (e) {
error = e.toString();
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
if (error == null) _error = 'No Error Dectected';
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
RaisedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
),
);
}
}
Add dependecy of image_picker:
image_picker: ^0.8.4+3
Then make a method for selectImages():
final ImagePicker imagePicker = ImagePicker();
List<XFile>? imageFileList = [];
void selectImages() async {
final List<XFile>? selectedImages = await
imagePicker.pickMultiImage();
if (selectedImages!.isNotEmpty) {
imageFileList!.addAll(selectedImages);
}
print("Image List Length:" + imageFileList!.length.toString());
setState((){});
}
Create a builder for showing selected Images:
return Scaffold(
appBar: AppBar(
title: Text('Multiple Images'),
),
body: SafeArea(
child: Column(
children: [
ElevatedButton(
onPressed: () {
selectImages();
},
child: Text('Select Images'),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: GridView.builder(
itemCount: imageFileList!.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return Image.file(File(imageFileList![index].path),
fit: BoxFit.cover,);
}),
),
),
],
),
));
Complete Source code available in github link...
https://github.com/NishaJain24/multi_image_picker