Flutter Failed assertion: 'initialValue == null || controller == null': is not true - flutter

I am trying to fetch data entered in firestore to my TextFormField in order to make it as a profile updating section but while doing so I am facing this error Failed assertion: line 150 pos 15: 'initialValue == null || controller == null': is not true. I am unfamiliar with it can anyone please guide me where I am making mistake how can I resolve it? Also is its the correct approach I am making profile updating section. User will first enter the data, it will be empty by default and when the user will again come back to this screen the user should be shown the previous saved data that's exactly what I want.
Here's my code:
final TextEditingController _peopletohangoutwithController =
TextEditingController();// Controller
// rest of the code
FutureBuilder<DocumentSnapshot>(
future: FirebaseFirestore.instance
.collection("userpreferences")
.doc(FirebaseAuth.instance.currentUser!.uid)
.get(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
print(snapshot.hasData);
print(snapshot.data!["peopletohangoutwith"]);
}
return Column(
children: [
const SizedBox(
height: 50,
),
Row(
children: [
Align(
alignment: Alignment.topLeft,
child: DelayedDisplay(
delay: const Duration(seconds: 1),
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: IconButton(
icon: const Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
onPressed: () {
Navigator.of(context).pop();
},
),
)),
),
const Align(
alignment: Alignment.topCenter,
child: DelayedDisplay(
delay: Duration(seconds: 1),
child: Text(
"Hang out with",
style: TextStyle(
fontSize: 26,
color: Colors.white,
fontFamily: "ProductSans",
fontWeight: FontWeight.bold),
),
),
),
],
),
const SizedBox(
height: 50,
),
const DelayedDisplay(
delay: Duration(seconds: 2),
child: Center(
child: Padding(
padding: EdgeInsets.only(left: 10, right: 10),
child: Text(
"What type of people you want to hang out with",
style: TextStyle(
fontSize: 20,
color: Colors.white,
fontFamily: "ProductSans",
fontWeight: FontWeight.bold),
),
),
),
),
const SizedBox(
height: 50,
),
DelayedDisplay(
delay: const Duration(seconds: 2),
child: Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: TextFormField(
initialValue: snapshot.data!["peopletohangoutwith"],
controller: _peopletohangoutwithController,
maxLines: 10,
decoration: InputDecoration(
hintText: "Write in as detail as possible",
fillColor: Colors.white,
filled: true,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(0),
borderSide: const BorderSide(
color: Colors.white,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(0),
borderSide: const BorderSide(
color: Colors.white,
width: 2.0,
),
),
)),
),
),
const SizedBox(
height: 100,
),
DelayedDisplay(
delay: const Duration(seconds: 2),
child: Center(
child: FloatingActionButton.extended(
label: const Text('Save'),
backgroundColor: const Color(0xFF2A3B6A),
icon: const Icon(
Icons.save_as_outlined,
size: 24.0,
),
onPressed: () async {
if (_peopletohangoutwithController.text.isEmpty) {
Get.snackbar(
"Error",
"Please explain your preference",
colorText: Colors.white,
);
} else {
FirebaseFirestore.instance
.collection("userpreferences")
.doc(FirebaseAuth.instance.currentUser!.uid)
.set({
"peopletohangoutwith":
_peopletohangoutwithController.text,
});
}
},
),
),
),
],
);
},
),

How bout you fetch the user data before going to the edit page.. Pass the data to the page in a constructor and enter the data in the text editing controller in init state.
EDIT: Sorry. Didn't knoqw you were a beginner.
Let's assume you're getting your data from some database eg Firebase. Ensure you have a usermodel. Models make data so much easier to manage.
Soo,,
class UserModel{
String _userName;
String _tikTok;
String get userName => _userName;
String get tiktok => _tikTok;
UserModel.fromSnapshot(DocumentSnapshot snapshot){
_userName = snapshot.data()["userName"];
_tikTok = snapshot.data()["tikTok"];
}
}
This userModel can be used to propagate the profile page. Eg, if you got the data from firestore using streamBuilder, the builder would be sth like
(context, snapshot){
if(!snapshot.hasData}{
return LoadingWidget();
}else{
UserModel userModel = UserModel.fromSnapshot(snapshot.data);
return Scaffold(body: blah blah Text(userModel.userName) `and so forth`
I lost track of my brackets there, but you get the point.
Send the userModel to the next page via constructors, and initiate the data in initstate. Coz init state is the first function executed the moment the page loads. Even before it starts building widgets.
This is the code for the edit page.
class EditProfilePage extends StatefulWidget {
final UserModel userModel;
EditProfilePage({
Key key,
#required this.userModel,
}) : super(key: key);
#override
State<EditProfilePage> createState() => _EditProfilePageState();
}
class _EditProfilePageState extends State<EditProfilePage> {
TextEditingController nameController;
TextEditingController tiktokAccountController;
#override
void initState() {
super.initState();
if (widget.userModel != null) {
nameController = TextEditingController(
text: widget.userModel.userName,
);
tiktokAccountController = TextEditingController(
text: widget.userModel.tiktok,
);
}
}
#override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: nameController,
decoration: InputDecoration(
hintText: "Username",
),
),
SizedBox(
height: 10,
),
TextField(
controller: tiktokAccountController,
decoration: InputDecoration(
hintText: "Tik Tok Username",
),
),
],
);
}
}
So, when you're going to the edit page from the profile page, you would call Navigator.of(context).push(EditBlahBlah(userModel: userModel,),)
Where userModel is the userModel you're viewing on the profile page. I hope that helps.

Only one of the TextFormField's initialValue or controller can be used.
Use TextEditingController with initial value:
final controller = TextEditingController('the initial value');

Related

After new Login app show old user data from firebase

I am trying to display current user data from Firebase, and it works totally fine, but when I logout and login with a new email ID, the app also shows previous user data instead of new user login data.
My signIn function in Signin page
class LoginPage extends StatefulWidget {
//when user is login then save their userid and after use this for fetching current user data
//this help in StudentData.dart page
var userId;
#override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final emailController = TextEditingController();
final passwordController = TextEditingController();
//for Validation
final _key = GlobalKey<FormState>();
//for geeting input and store email & password
var email = "";
var password = "";
//for Loading Indicator
bool isLodaing = false;
//for login
Future userLogin() async {
//check internet is on or not
final ip = context.read<InternetProvider>();
await ip.checkInternetConnection();
//for checking Internet
if (ip.hasInternet == false) {
openSnackbar(context, "Check your internet connection", Colors.red);
} else {
try {
UserCredential userCredential = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password);
//when user loged in that time save user id that help after for fetch data in StudentData.dart page
// widget.userId = userCredential.user!.uid;
setState(() {
widget.userId = userCredential.user!.uid;
print("User id is : " + userCredential.user!.uid);
});
print("Widget User id is : " + widget.userId);
//show succuful log-in meesage
openSnackbar(
context, "Log-in Successfull", Color.fromARGB(255, 70, 213, 92));
//after login go to profile Page
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => FirstPage()));
} on FirebaseAuthException catch (e) {
//for no user Found
if (e.code == 'user-not-found') {
//for stoping the loading indicator when user get this error
Future.delayed(
Duration(seconds: 0),
() {
setState(() {
isLodaing = false;
});
},
);
//show Snack Bar when this error occur
openSnackbar(context, "No User Found for this e-mail", Colors.red);
}
//for Wrong Password
else if (e.code == 'wrong-password') {
//for stoping the loading indicator when user get this error
Future.delayed(
Duration(seconds: 0),
() {
setState(() {
isLodaing = false;
});
},
);
//show Snack Bar when this error occur
openSnackbar(context, "Wrong Password", Colors.red);
}
}
}
}
#override
void dispose() {
emailController.dispose();
passwordController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: HexColor("#F9B684"),
body: GestureDetector(
//when user tap on screen tahat time keybord disumissed
//this is use for avoiding overflow screen
onTap: () => FocusScope.of(context).unfocus(),
child: SingleChildScrollView(
child: Column(
// this is main Column
children: [
//Heading
Container(
margin: EdgeInsets.only(top: 80, left: 20),
padding: EdgeInsets.only(left: 75, top: 13),
height: 80,
width: 265,
// color: Colors.white,
child: Text(
'Login',
style: TextStyle(
fontFamily: 'Ubuntu',
fontWeight: FontWeight.bold,
fontSize: 43,
color: HexColor("#2D0C03"),
),
),
),
//for image
Container(
margin: EdgeInsets.only(left: 10),
height: 200,
width: 265,
// color: Colors.white,
child: Image.asset("assets/images/login.gif",
fit: BoxFit.cover),
),
const SizedBox(height: 17),
//for TextFileds
Form(
key: _key,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 23.0),
child: Column(
children: [
//for E-mail Text Filed
TextFormField(
keyboardType: TextInputType.emailAddress,
//for move to cursor next Text automatically
textInputAction: TextInputAction.next,
//for autofil e-mail
autofillHints: [AutofillHints.email],
controller: emailController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
prefixIcon: Icon(
Icons.email,
color: HexColor("#002C00"),
),
hintText: "e-mail",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(33)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: HexColor("#002C00")),
borderRadius: BorderRadius.circular(25.7),
),
enabledBorder: UnderlineInputBorder(
borderSide:
const BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(25.7),
),
),
//for validation
validator: (value) =>
value != null && !EmailValidator.validate(value)
? 'Enter valid e-mail'
: null,
),
const SizedBox(height: 10),
//for Password Text Filed
TextFormField(
controller: passwordController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
prefixIcon: Icon(
Icons.password,
color: HexColor("#002C00"),
),
hintText: "password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(33)),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: HexColor("#002C00")),
borderRadius: BorderRadius.circular(25.7),
),
enabledBorder: UnderlineInputBorder(
borderSide:
const BorderSide(color: Colors.white),
borderRadius: BorderRadius.circular(25.7),
),
),
//for validation
validator: (value) {
if (value == null || value.isEmpty) {
return "Please enter password";
}
return null;
},
),
//for forget Password
Container(
margin: const EdgeInsets.only(top: 4),
// color: Colors.yellow,
height: 35,
width: MediaQuery.of(context).size.width,
alignment: Alignment.bottomRight,
child: TextButton(
onPressed: () {
//goto Forget Password Screen
nextScreen(context, ForgetPassword_Page());
},
child: const Text(
"Forgot Password",
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Gotham',
color: Color(0xff1778F2),
fontSize: 14.5),
),
),
),
const SizedBox(height: 9),
//for sign-in Button
SizedBox(
height: 50,
width: 170,
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: HexColor("#98504B"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
),
//for loading indicator and Text
icon: isLodaing
? const SizedBox()
: const Icon(Icons.arrow_forward, size: 24),
label: isLodaing
? Row(
children: [
//for circular indicator
Container(
margin:
const EdgeInsets.only(left: 7),
height: 25,
width: 25,
child: CircularProgressIndicator(
color: HexColor("#2D0C03"),
strokeWidth: 3.5,
backgroundColor: Colors.white,
),
),
//for text
Container(
margin:
const EdgeInsets.only(left: 7),
child: Text(
"Please Wait..",
style: TextStyle(
fontFamily: 'Gotham',
color: Colors.white),
),
),
],
)
: const Text(
'Sign-in',
style: const TextStyle(
fontFamily: 'Gotham', fontSize: 22),
),
//here we call method name signup for storing data in firebase
onPressed: () async {
//for validation
if (_key.currentState!.validate()) {
isLodaing = true;
setState(() {
//when user enter email & password then store those email and passwors in variable which intialize in top
email = emailController.text;
password = passwordController.text;
});
//for Showing Loaing Indicator
Future.delayed(
Duration(seconds: 3),
() {
setState(() {
isLodaing = true;
});
},
);
//for user login
userLogin();
}
//after run above line of code this Stop the Loading Indicator
Future.delayed(
Duration(seconds: 3),
() {
setState(() {
isLodaing = false;
});
},
);
},
),
),
//for sign-up opotion below login button
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Does Not Have Account? '),
TextButton(
onPressed: () {
nextScreen(context, RegistrationPage());
},
child: const Text(
"Sign-UP",
style: TextStyle(
letterSpacing: 0.2,
fontFamily: "Ubuntu",
fontSize: 16,
color: Color(0xff1778F2),
),
),
)
],
),
),
],
),
),
),
]),
),
),
),
);
}
}
UserData controller Class:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:get/get.dart';
import 'package:gtu_all_in_one/Pages/LoginPage.dart';
//this class help for fetching current user info from firebase
class StudentDataController extends GetxController {
final firebaseInstance = FirebaseFirestore.instance;
//after data fetch insert data in this
Map StudentProfileData = {
'name': '',
'EnrollmentNo': '',
'Email': '',
'Branch&Sem': ''
};
//create loginpage instance for getting current user userid , using this we fetch the data
LoginPage authController = LoginPage();
#override
void onReady() {
super.onReady();
getStudentProfileData();
}
Future<void> getStudentProfileData() async {
// print("user id ${authController.userId}");
try {
var response = await firebaseInstance
.collection('users')
.where('user_Id', isEqualTo: authController.userId)
.get();
// response.docs.forEach((result) {
// print(result.data());
// });
if (response.docs.length > 0) {
StudentProfileData['name'] = response.docs[0]['name'];
StudentProfileData['EnrollmentNo'] = response.docs[0]['EnrollmentNo'];
StudentProfileData['Email'] = response.docs[0]['Email'];
StudentProfileData['Branch&Sem'] = response.docs[0]['Branch&Sem'];
}
print(StudentProfileData);
} on FirebaseException catch (e) {
print(e);
} catch (error) {
print(error);
}
}
}
And profile Page where i trying to display current user data:
class ProfilePage extends StatefulWidget {
const ProfilePage({Key? key}) : super(key: key);
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
//when user come in profile page after login that time this create instance of StudentDataController and go to StudentData Page
final StudentDataController controller = Get.put(StudentDataController());
#override
Widget build(BuildContext context) {
// for logout button
final sp = context.watch<SignInProvider>();
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
body: Center(
child: Column(
children: [
SizedBox(height: 300),
Text("Name : ${controller.StudentProfileData['name']} "),
Text(
"Enrollment No : ${controller.StudentProfileData['EnrollmentNo']} "),
Text("Email : ${controller.StudentProfileData['Email']} "),
Text(
" Branch& Sem : ${controller.StudentProfileData['Branch&Sem']} "),
SizedBox(height: 10),
SizedBox(height: 10),
//for Opening QR Code Scanner
SizedBox(
height: 50,
width: 250,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: HexColor("#48EDC5"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22),
),
),
child: Row(
children: [
//for text
Container(
margin: const EdgeInsets.only(left: 13),
child: Text(
"Mark Attendance",
style: TextStyle(
fontFamily: 'Gotham',
color: HexColor("#002C00"),
fontSize: 20),
),
),
//for Icone
Container(
margin: EdgeInsets.only(left: 5),
child: Icon(
Icons.qr_code_scanner,
size: 22,
color: HexColor("#002C00"),
),
),
],
),
//goto QR Code Scanner Page
onPressed: () {
nextScreen(context, QRCodeScanner());
},
),
),
SizedBox(height: 10),
//for LogOut Button
SizedBox(
height: 50,
width: 150,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: HexColor("#48EDC5"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22),
),
),
child: Row(
children: [
//for text
Container(
margin: const EdgeInsets.only(left: 13),
child: Text(
"log Out",
style: TextStyle(
fontFamily: 'Gotham',
color: HexColor("#002C00"),
fontSize: 20),
),
),
//for Icone
Container(
margin: EdgeInsets.only(left: 5),
child: Icon(
Icons.arrow_forward_ios,
size: 22,
color: HexColor("#002C00"),
),
),
],
),
//goto SignUp Page
onPressed: () {
sp.userSignOut();
nextScreenReplace(context, FirstPage());
},
),
),
],
),
),
),
);
}
}

how to display input value from text field to other pages?

I'm trying to display the input value below onto another page that contains radio buttons . my aim is that every time i write or change a value in a textfield it gets updated and displays onto a different page with the radio options . The snippet of code below is for the textfield - i used riverpod to connect it to firestore:
class AddMealPage extends ConsumerWidget {
const AddMealPage({Key? key}) : super(key: key);
static const String route = "/addMeal";
#override
Widget build(BuildContext context, WidgetRef ref) {
final model = ref.read(addMealProvider);
return LoadingLayer(
child: Scaffold(
appBar: AppBar(
elevation: 0,
iconTheme: const IconThemeData(
color: Colors.black,
),
title: const Text(
"Create Meal",
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
backgroundColor: Colors.white,
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
child: MaterialButton(
padding: const EdgeInsets.all(16),
color: Colors.black,
onPressed: model.enabled
? () async {
try {
await model.writeMeal();
Navigator.pop(context);
} catch (e) {
AppSnackbar(context).error(e);
}
}
: null,
child: const Text(
"Add meal",
style: TextStyle(color: Color.fromARGB(255, 247, 245, 245)),
),
),
),
body: SingleChildScrollView(
child: Container(
padding:
const EdgeInsets.symmetric(vertical: 60.0, horizontal: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
GestureDetector(
onTap: () async {
final picked = await ImagePicker()
.pickImage(source: ImageSource.gallery);
if (picked != null) {
model.file = File(picked.path);
}
},
child: Container(
margin: const EdgeInsets.only(),
width: MediaQuery.of(context).size.width,
height: 210.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: (model.mealUrl != null || model.file != null)
? DecorationImage(
image: model.file != null
? FileImage(model.file!)
: NetworkImage(model.mealUrl!)
as ImageProvider,
fit: BoxFit.cover,
)
: null),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (model.mealUrl == null && model.file == null)
const Expanded(
child: Center(
child: Icon(
Icons.photo,
),
),
),
const Material(
color: Colors.transparent,
child: Padding(
padding: EdgeInsets.all(8.0),
),
),
],
),
),
),
const SizedBox(
height: 10,
),
const Padding(
padding: EdgeInsets.only(left: 15.0),
child: Text(
"Meal Name",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
),
),
Container(
height: 50,
padding: const EdgeInsets.only(top: 10),
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.symmetric(horizontal: 20),
child: TextFormField(
textInputAction: TextInputAction.done,
initialValue: model.mealName,
maxLines: 1,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.grey),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(color: Colors.grey),
),
),
onChanged: (v) => model.mealName = v,
),
),
I want to display the input value i get from the textfield above in the format of a radioButton on a seperate page :
enum Variant { mealName }
class RadioOption extends StatefulWidget {
const RadioOption({Key? key}) : super(key: key);
#override
State<RadioOption> createState() => _RadioOptionState();
}
class _RadioOptionState extends State<RadioOption> {
Variant? _character = Variant.mealName;
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RadioListTile<Variant>(
title: const Text('$mealName'),
value: Variant.MealName,
groupValue: _character,
onChanged: (Variant? value) {
setState(() {
_character = value;
});
},
),
I don't see the whole architecture of the app. But if you want to transfer model.mealName, you can make String value (mealName) in your RadioOption, and pass it through the constructor:
final mealName;
RadioOption({required this.mealName});
And then access it in _RadioOptionState by:
title: const Text(widget.mealName);
You can use TextEditingController and add this controller to your TextFormField which have controller properties but you can't use initialValue and controller both so avoid initialValue. To put value you can use controller.text = your_value;
You value will be filled in text field.
To get value from TextFormField Use var newValue = controller.text; and send this newValue to another page in constructor.

SingleChildScrollView not working for password textfield in Flutter

I am currently creating my first flutter application. So, when I was testing the login and sign up page. I encountered a problem.
The SingleChildScrollView() is not working in my Flutter login and Signin page for the password textfield only. The SingleChildScrollView() works perfectly for the email textfield. Can someone help me .
Code of Login page :
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:secure_pass/constants/routes.dart';
import 'package:secure_pass/services/auth/auth_exceptions.dart';
import 'package:secure_pass/services/auth/auth_service.dart';
import 'package:secure_pass/utilities/dialogs/error_dialog.dart';
class LoginView extends StatefulWidget {
const LoginView({Key? key}) : super(key: key);
#override
State<LoginView> createState() => _LoginViewState();
}
class _LoginViewState extends State<LoginView> {
late final TextEditingController _email;
late final TextEditingController _password;
#override
void initState() {
_email = TextEditingController();
_password = TextEditingController();
super.initState();
}
#override
void dispose() {
_email.dispose();
_password.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[300],
body: SafeArea(
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children:[
//App icon
Icon(
Icons.android,
size: 100,
),
SizedBox(height: 25),
//Hello Again
Text(
'Hello Again!',
style: GoogleFonts.bebasNeue(
fontSize: 52,
),
),
SizedBox(height: 10),
Text(
'Welcome back, you\'ve been missed!',
style: TextStyle(
fontSize: 20,
),
),
SizedBox(height: 50),
//email textfield
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: TextField(
controller: _email,
enableSuggestions: false,
autocorrect: false,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
hintText: 'Enter your email here',
border: InputBorder.none
),
),
),
),
),
SizedBox(height: 10),
//Password textfield
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: TextField(
controller: _password,
obscureText: true,
enableSuggestions: false,
autocorrect: false,
decoration: const InputDecoration(
hintText: 'Enter your password here',
border: InputBorder.none
),
),
),
),
),
SizedBox(height: 10),
TextButton(
onPressed: () async {
final email = _email.text;
final password = _password.text;
try {
await AuthService.firebase().logIn(
email: email,
password: password,
);
final user = AuthService.firebase().currentUser;
if (user?.isEmailVerified ?? false) {
// user's email is verified
Navigator.of(context).pushNamedAndRemoveUntil(
passwordsRoute,
(route) => false,
);
} else {
// user's email is NOT verified
Navigator.of(context).pushNamedAndRemoveUntil(
verifyEmailRoute,
(route) => false,
);
}
} on UserNotFoundAuthException {
await showErrorDialog(
context,
'User not found',
);
} on WrongPasswordAuthException {
await showErrorDialog(
context,
'Wrong credentials',
);
} on GenericAuthException {
await showErrorDialog(
context,
'Authentication error',
);
}
},
//log in button
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: const Text(
'Login',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
),
),
),
SizedBox(height: 25),
TextButton(
onPressed: () {
Navigator.of(context).pushNamedAndRemoveUntil(
registerRoute,
(route) => false,
);
},
//Not Registered yet ?
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const[
Text(
'Not registered yet?',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(
' Register now',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
],
),
)
],
),
),
),
),
);
}
}
You can add bottom padding to the email text field.
Padding(
padding: const EdgeInsets.only(
left: 25,
right: 25,
bottom: MediaQuery.of(context).viewInsets.bottom + 32.0,
),
I assume you want both the email and the password textfield to come up, when the user is entering his data in the respective text fields.
In order to achieve in your scaffold set resizeToAvoidBottomInset property to true and it will work fine
Just Add reverse: true on SingleChildScrollView.
child: Center(
child: SingleChildScrollView(
reverse: true,
child: Column(
I was able to solve the problem by removing the "Center" widget.

List of text in one Card using ListView.builder twice and for loop?

With my current code, my list is put into separate cards. I need it to be in one. I'm using two ListView.builders and a loop. I believe that's what's causing the problem. Please tell me if I'm wrong.
Every time the user taps submit on my second TextField a new TextField appears, functionality I would like to keep one way or another.
I'm just staring out so any help if appreciated.
My end goal is to have a bullet point list but the bullet points aren't important right now.
Here's my code:
class PostNote extends StatefulWidget {
User user;
PostNote({
required this.user,
});
#override
State<PostNote> createState() => _PostNoteState();
}
class _PostNoteState extends State<PostNote> {
FirebaseFirestore firestore = FirebaseFirestore.instance;
TextEditingController titleController = TextEditingController();
final List<TextField> _textFields = [];
final List<TextEditingController> _controllers = [];
bool loading = false;
#override
void initState() {
super.initState();
_addTextField();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF162242),
elevation: 0,
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
Text(
"Title",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(
height: 15,
),
Container(
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
color: Colors.white,
),
padding: EdgeInsets.only(left: 10, right: 10),
child: TextField(
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.transparent),
),
),
textInputAction: TextInputAction.next,
style: TextStyle(
color: Color(0xFF192A4F),
fontSize: 18,
),
controller: titleController,
autofocus: true,
),
),
SizedBox(
height: 30,
),
Text(
"Notes",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(
height: 15,
),
Container(
padding: EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
color: Colors.white,
),
child: ListView.builder( // HERE
shrinkWrap: true,
itemCount: _textFields.length,
itemBuilder: (_, index) {
return _textFields[index];
},
),
),
SizedBox(
height: 50,
),
loading
? Center(
child: CircularProgressIndicator(),
)
: Container(
height: 50,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
child: Text(
"Add Note",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Color(0xFF162242)),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
),
onPressed: () async {
for (var notesController in _controllers) // HERE {
if (titleController.text == "" ||
notesController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("All fields are required")));
} else {
setState(() {
loading = true;
});
await FirestoreServiceEdit().insertNote(
titleController.text,
notesController.text,
widget.user.uid);
CollectionReference notes =
firestore.collection('notes');
QuerySnapshot allResults = await notes.get();
allResults.docs.forEach((DocumentSnapshot result) {
print(result.data());
});
if (!mounted) return;
setState(() {
loading = false;
});
Navigator.pop(context);
}
}
}),
),
]),
),
),
),
);
}
void _addTextField() {
final notesController = TextEditingController();
_textFields.add(
TextField(
decoration: InputDecoration(
prefix: Icon(
Icons.circle,
size: 8,
color: Colors.black,
),
),
autofocus: true,
controller: notesController,
onSubmitted: (_) => setState(() => _addTextField()),
),
);
_controllers.add(notesController);
}
}
class FirestoreServiceEdit{
FirebaseFirestore firestore = FirebaseFirestore.instance;
Future insertNote(String title, String notes, String? userId,)async{
try{
await firestore.collection('notes').add({
"title":title,
"notes":notes,
"userId":userId
});
} catch (e) {}
}
}
class NoteModelEdit {
String id;
String title;
String notes;
String userId;
NoteModelEdit({
required this.id,
required this.title,
required this.notes,
required this.userId
});
factory NoteModelEdit.fromJson(DocumentSnapshot snapshot){
return NoteModelEdit(
id: snapshot.id,
title: snapshot['title'],
notes: snapshot['notes'],
userId: snapshot['userId']
);
}
}
Home screen:
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("notes")
.where('userId', isEqualTo: user.uid)
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
if (snapshot.data.docs.length > 0) {
return ListView.builder( // HERE
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
NoteModelEdit note =
NoteModelEdit.fromJson(snapshot.data.docs[index]);
return Card(
margin: EdgeInsets.only(top: 18, left: 15, right: 15),
child: Column(children: [
ListTile(
title: Center(
child: Container(
padding: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 0.5),
),
),
child: Text(
note.title,
textWidthBasis: TextWidthBasis.longestLine,
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.w600),
textAlign: TextAlign.center,
),
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditNoteScreen(),
));
},
),
SizedBox(
height: 15,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
note.notes,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w700),
),
),
SizedBox(
height: 15,
),
]),
);
});
Thank you for your time!
You will need to augment your logic to look at all the TextFields at the same time rather than one at a time and inserting a note for each.
if (titleController.text.isEmpty ||
_controllers.any((element) => element.text.isEmpty)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text("All fields are required")));
} else {
setState(() {
loading = true;
});
}
await FirestoreServiceEdit().insertNote(
titleController.text,
_controllers.map((element) => element.text).join("\n"),
widget.user.uid);
you can do like this :
Widget listInCard() {
List testList = ["note1", "note2", "note3"];
return Card(
color: Colors.blue.shade200,
elevation: 5,
child: ListView.builder(
itemCount: testList.length,
itemBuilder: (context, index) {
return Text(testList[index]);
}),
);
}
The blue color is the Card and inside it, it is a list of notes.
You can also use Container instead of Card.

Flutter Riverpod for local and global variables

i have two text editing controllers, im trying to give those text editing controllers initial values fetched from the api. I need to declare the text editing controllers globaly and give the initial value from the api, so what i need is to use data3.firstName and data3.lastName to the global variables, if i try declaring the variables and the function inside build it doesnt work, so just need to use the fetched data to global text editing controllers so i can give initial values.
late Future<Response> futureData;
#override
void initState() {
super.initState();
futureData = fetchAccountData();
}
final _formKey = GlobalKey<FormState>();
TextEditingController editedFirstName =
TextEditingController(text: 'Hello'); // needs to be data3.firsName
TextEditingController editedLastName = TextEditingController(text: 'Riverpod looks great');// needs to be data3.lastName
Future<void> putAccountData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? authorization = prefs.getString('authorization');
var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';
Map payload = {
"firstName": editedFirstName.text,
"lastName": editedLastName.text,
};
try {
final response = await http.put(Uri.parse(url),
headers: <String, String>{
'authorization': authorization ?? basicAuth.toString(),
"Content-Type": "application/json"
},
body: jsonEncode(payload));
} catch (er) {}
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return SafeArea(
child: WillPopScope(
onWillPop: () async {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
return shouldPop;
},
child: KeyboardDismisser(
gestures: const [
GestureType.onTap,
GestureType.onPanUpdateDownDirection
],
child: Form(
key: _formKey,
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Colors.blue,
title: const Text(
'Edit My Profile',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const ProfileScreen(),
),
);
},
),
),
body: FutureBuilder<Response>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
AccountData data3 = AccountData.fromJson(
json.decode(snapshot.data!.body),
);
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: width,
height: height / 1.9,
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 3,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
children: [
const Padding(
padding: EdgeInsets.all(30),
child: Text(
"First Name:",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(30),
child: SizedBox(
width: width / 2.5,
child: Center(
child: TextFormField(
textAlignVertical:
TextAlignVertical.center,
//initialValue: editedFirstName.text = data3.firstName,
controller: editedFirstName,
// ..selection =
// TextSelection.collapsed(
// offset: data3
// .firstName.length),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
borderSide: const BorderSide(
color: Colors.red,
width: 1),
),
),
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
// inputFormatters: [
// LengthLimitingTextInputFormatter(15)
// ],
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Name is required';
}
return null;
},
),
),
),
),
],
),
Row(
children: [
const Padding(
padding: EdgeInsets.all(30),
child: Text(
'Last Name:',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(30),
child: SizedBox(
width: width / 2.5,
child: TextFormField(
//initialValue: editedLastName.text = data3.lastName,
controller: editedLastName,
// ..selection =
// TextSelection.collapsed(
// offset:
// data3.lastName.length),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 10.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10),
),
),
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold),
),
),
),
],
),
Looks like you want to provide an initial value to TextField, but the value is async fetched from the server.
You are on the right track to use a TextEditingController, but since you won't have the value ready at first, you should not use TextEditingController(text: 'Hello') when creating the controller.
Instead, you can create a controller without a default value, for example: final _controller = TextEditingController(). And then after you got the data, say after calling fetchAccountData() method in initState, you can assign the data to the controller using _controller.text = fetchedValue.
I see you are also using FutureBuilder. Depending on what you want to display before the "default values" are loaded, you might or might not need the FutureBuilder anymore.
Quick demo:
class QuickDemo extends StatefulWidget {
const QuickDemo({Key? key}) : super(key: key);
#override
_QuickDemoState createState() => _QuickDemoState();
}
class _QuickDemoState extends State<QuickDemo> {
final _controller = TextEditingController();
#override
void initState() {
super.initState();
_fetchData();
}
_fetchData() async {
// do your network call here
await Future.delayed(const Duration(seconds: 1));
// and then parse your response here
final data = 'Hello';
// eventually you will have data, so assign it:
_controller.text = data;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(
controller: _controller,
),
),
);
}
}