I have the following code that initially displays a blank page, but I'd like an rAlert dialog to display automatically. Once the user clicks 'Request' or 'Cancel', some text will be displayed on the screen.
But I can't get the code to run that displays the Alert. I had it working by showing a button and clicking the button, but i need the Alert to display automatically when the page is displayed. I tried putting it in the initState. I didn't get any errors, but it didn't work either.
Anyone know what I need to do? Thanks?
import 'package:flutter/material.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'dart:async';
import 'package:rostermeon/cwidgets/general_widgets.dart';
import 'package:rostermeon/rmo_constants.dart';
class ForgotPassword extends StatefulWidget {
static const String id = 'forgot_password_screen';
#override
_ForgotPasswordState createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends State<ForgotPassword> {
StreamController<bool> _events;
#override
initState() {
super.initState();
_events = new StreamController<bool>();
doRequest(context: context);
}
Future<bool> doSaveRequest({String pReason}) async {
await Future.delayed(const Duration(seconds: 3), () {});
return false;
}
Future<bool> doRequest({context}) {
String _reason = '';
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
TextEditingController reasonController = TextEditingController();
TextStyle _style = TextStyle(fontFamily: 'Montserrat', fontSize: 18.0, fontWeight: FontWeight.normal);
InputDecoration _textFormFieldDecoration({String hintText, double padding}) => InputDecoration(
//contentPadding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 8.0),
contentPadding: EdgeInsets.all(padding),
isDense: true,
hintText: hintText,
hintStyle: TextStyle(color: kHintText),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
);
return Alert(
context: context,
title: 'Request New Password',
content: StreamBuilder<bool>(
initialData: false,
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
print(" ${snapshot.data.toString()}");
return snapshot.data
? CircularProgressIndicator()
: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 20.0),
Text('Email', textAlign: TextAlign.left, style: _style),
SizedBox(height: 10.0),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "please enter email";
}
return null;
},
onSaved: (value) {
_reason = value;
},
decoration: _textFormFieldDecoration(
hintText: 'your email address',
padding: 8.0,
),
controller: reasonController,
),
SizedBox(height: 10.0),
],
),
);
}),
buttons: [
DialogButton(
child: Text('Request', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print(_reason);
_events.add(true);
var saved = await doSaveRequest(pReason: _reason);
if (saved) {
Navigator.pop(context, false);
} else {
_events.add(false);
}
Navigator.of(context).pop();
// Navigator.pop(context, false);
}
},
),
DialogButton(
child: Text('Cancel', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () {
Navigator.pop(context, false);
},
),
],
).show();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: rmoAppBar(subText: 'Request New Password', hideBackButton: false),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
),
),
);
}
}
Dialogs/Alerts need the buildContext in order to work, You can't have the buildContext before build() method is called, that's why you can't just call it in initstate() before the build is called.
To make it work use addPostFrameCallback to make sure it delays until widget is built:
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => yourMethod(context));
}
https://www.didierboelens.com/2019/04/addpostframecallback/
Related
I'm stuck with one issue where once I click on the upload image button it will take me to the next page wherein upload image class I will choose the images from the camera or Gallery and I will click on done. In the done button I have written navigation. pop(context) to the first page but when I come back all the text field data is cleared whatever I have entered and again I need to enter it back which is quite frustrating all the time...PLease help me to solve the issue or show the way how to save the data?
import '../blocs/addtrip_bloc.dart';
import '../widgets/customtextformfield.dart';
import 'CameraWidgetState.dart';
class DataInfoPage extends StatefulWidget {
const DataInfoPage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<DataInfoPage> {
_DataInfoPageState createState() => _DataInfoPageState();
String date = "";
final FirebaseAuth _auth = FirebaseAuth.instance;
User? user;
var name = '';
#override
void initState() {
super.initState();
initUser();
savedata();
}
initUser() async {
user = (await _auth.currentUser!);
name = user!.displayName!;
setState(() {});
}
void savedata() {
final absavedata = context.read<AddTripBloc>();
}
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
DateTime selectedDate = DateTime.now();
TextEditingController tripname = new TextEditingController();
TextEditingController sdate = new TextEditingController();
DateTimeRange? _selectedDateRange;
String _displayText(String begin, DateTime? date) {
if (date != null) {
return '$begin Date: ${date.toString().split(' ')[0]}';
} else {
return 'Press the button to show the picker';
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
SizedBox(
height: 20,
),
Text(
"Please enter trip details ",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 25,
color: Colors.black),
),
SizedBox(
height: 20,
),
Padding(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
customfields(
hintValue: ' Enter Trip Name',
labeltxt: 'Trip Name *',
keyboardtype: TextInputType.text,
text: tripname),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: _show,
child: const Icon(Icons.date_range),
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.circular(5))),
Column(
children: [
Text(
_displayText(
'Start', _selectedDateRange?.start),
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Colors.black),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () async {
await Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CameraWidget()));
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => CameraWidget()));
},
child: const Text("Upload Images of Trip *"),
),
SizedBox(
height: 35,
),
],
)),
],
),
),
));
}
void _show() async {
final DateTimeRange? result = await showDateRangePicker(
context: context,
firstDate: DateTime(2022, 1, 1),
lastDate: DateTime(2030, 12, 31),
currentDate: DateTime.now(),
saveText: 'Done.',
);
if (result != null) {
// Rebuild the UI
print(result.start.toString());
setState(() {
_selectedDateRange = result;
});
}
}
}
Custom Flied Code
class customfields extends StatelessWidget {
customfields(
{required this.hintValue,
this.labeltxt = "",
required this.keyboardtype,
this.maxvalue = 1,
required this.text});
String hintValue;
String labeltxt;
int maxvalue;
TextInputType keyboardtype;
TextEditingController text;
bool _validate = false;
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
TextFormField(
controller: text,
cursorColor: Colors.black,
//textAlign: TextAlign.left,
// autocorrect: true,
// textInputAction: TextInputAction.go,
// maxLines: maxvalue,
// autofocus: true,
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
textAlignVertical: TextAlignVertical.center,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp('[a-z A-Z 0-9 #?!#%^&* ? # ^_ . : ! | "" \'-]')),
],
decoration: InputDecoration(
border: new UnderlineInputBorder(
// borderRadius: new BorderRadius.circular(5.0),
// borderSide: new BorderSide(),
),
hintText: hintValue,
labelText: labeltxt,
errorText: _validate ? 'Value Can\'t Be Empty' : null,
//prefixIcon: Icon(Icons),
//suffixIcon: Icon(Icons.currency_bitcoin)
),
keyboardType: keyboardtype,
validator: (value) {
if (value!.isEmpty) {
return "Value Can't be empty.";
}
return null;
},
),
],
),
);
}
}
Recently implemented a tagForm widget at "+" button press, I want to delete those widgets now at "delete" button press, but right now, even when I press the "delete" button, nothing happens.
How can I solve this?
Any help appreciated!
code:
import 'package:flutter/material.dart';
import '../database/firestoreHandler.dart';
import '../models/todo2.dart';
import '../widgets/dialogs.dart';
class TodoEdit extends StatefulWidget {
String? doctitle;
String? doctdescription;
String? docimage;
String? docid;
List? doctags;
TodoEdit({Key? key, this.doctitle, this.doctdescription, this.docimage, this.docid,this.doctags}) : super(key: key);
#override
_TodoEditState createState() => _TodoEditState();
}
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
var textEditingControllers = <TextEditingController>[];
//-----------------the list where the form is stored----------
var textformFields = <Widget>[];
void _addformWidget(controller) {
setState(() {
textformFields.add(tagForm(controller));
});
}
//------------------------------------------------------------------------
Widget tagForm(controller){
return TextFormField(
controller: controller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Tag",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
suffixIcon: IconButton(
icon:Icon(Icons.delete, color: Colors.white,),
//--------------------- doesn't work?-------------------
onPressed: (){
setState(() {
textformFields.remove(tagForm(controller));
});
},
--------------------------------------------------------------
)
),
);
}
//-----------------------------------------------------------
#override
void initState() {
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
widget.doctags?.forEach((element) {
var textEditingController = new TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
return _addformWidget(textEditingController);
//);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
actions: [
IconButton(onPressed: (){
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: Text('Delete TODO'),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Delete'),
onPressed: () {
deleteData(widget.docid.toString(), context);
setState(() {
showSnackBar(context, 'todo "${widget.doctitle}" successfully deleted!');
});
},
),
],
);
},
);
},
icon: Icon(Icons.delete))
],
backgroundColor: Colors.grey[900],
title: Text("${widget.doctitle}"),
),
body: Container(
child: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 10),
TextFormField(
controller: tcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Title",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: dcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Description",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: icontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Image url",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
Row(children: [
Text("Tags:", style:TextStyle(color: Colors.white)),
IconButton(onPressed: (){
var textEditingController = new TextEditingController(text: "tag");
textEditingControllers.add(textEditingController);
_addformWidget(textEditingController);
print(textformFields.length);
},
icon: Icon(Icons.add,color: Colors.white,),
)
],),
/*SingleChildScrollView(
child: new Column(
children: textformFields,
)
),*/
Expanded(
child: SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context,index) {
return textformFields[index];
}),
)
),
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
List<String> test = [];
textEditingControllers.forEach((element) {
test.add(element.text);
});
if(tcontroller == '' && dcontroller == '' && icontroller == ''){
print("not valid");
}else{
var todo = Todo2(
title: tcontroller.text,
description: dcontroller.text,
image: icontroller.text,
tags: test,
);
updateData(todo, widget.docid.toString(),context);
setState(() {
showSnackBar(context, 'todo ${widget.doctitle} successfully updated!');
});
}
},
child: Icon(Icons.update),
),
);
}
}
You can't remove anything from the list with objects from tagForm(controller), because these objects are newly created and therefore not the same as in the list (as long as the == operator is not overwritten)
If you still want to have the widgets in a list instead of just storing the controllers and without having to change much, you could remove the widgets like this:
onPressed: (){
setState(() {
controller.dispose();
textEditingControllers.remove(controller);
textformFields.removeWhere((w) => w.controller = controller));
});
},
and change the type of your List: var textformFields = <TextFormField>[]; and of the method TextFormField tagForm(controller).
In general, you can of course optimize the state management, but with this solution it should work for now.
Dont't store Widget, it is bad way. Insteads store there property, render by List then remove by index when you need.
ps: some code syntax can wrong, i write this on browser.
class _TodoEditState extends State<TodoEdit> {
...
var textformFields = <String>[];
...
void _addformWidget([String? initValue]) {
setState(() => textformFields.add(initValue ?? ""));
}
...
Widget tagForm(String value, void Function(String) onChange, void Function() onRemove){
var openEditor = () {
// Open dialog with text field to edit from [value] call onChange with
// new value
OpenDialog().then((newvalue) {
if(newvalue != null) onChange(newvalue);
}
};
var delete = () {
// Open confirm dialog then remove
OpenConfirmDialog("your message").then((continue) {
if(continue) onRemove();
});
};
return InkWell(
onTap: openEditor,
child: Text(value), // render your tag value
);
}
...
#override
void initState() {
...
textformFields = List.filled(widget.doctags ?? 0, ""); // or List.generate/map if you want replace by own value.
}
...
#override
Widget build(BuildContext context) {
...
ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context,index) => tagForm(
textformFields[index],
(newvalue) => setState(() => textformFields[index] = newvalue),
() => setState(() => textformFields = textformFields..removeAt(index));,
),
),
...
);
}
I'm having troubles with my list builder.
I'm trying to add more TextFormFields when the "+" button next to the "Tag" text is pressed, I'm fetching the tag list from firebase and then displaying every tag from that list in a separate TextFormField, but when I try to add a new TextFormField with the "+" button, nothing happens, I check if the list leght changes and indeed it changes, but nothing happens, what I would expect is to get a new TextFormField in the red square.
code:
import 'package:flutter/material.dart';
import '../database/firestoreHandler.dart';
import '../models/todo2.dart';
import '../widgets/dialogs.dart';
class TodoEdit extends StatefulWidget {
String? doctitle;
String? doctdescription;
String? docimage;
String? docid;
List? doctags;
TodoEdit({Key? key, this.doctitle, this.doctdescription, this.docimage, this.docid,this.doctags}) : super(key: key);
#override
_TodoEditState createState() => _TodoEditState();
}
// -----------------------------my widget------------
Widget tagForm(controller){
return TextFormField(
controller: controller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Tag",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
);
}
//---------------------------------------------------
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
//--------------------add widget to list----------------
void _addformWidget(list,controller) {
setState(() {
list.add(tagForm(controller));
});
}
//------------------------------------------------
#override
void initState() {
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
}
#override
Widget build(BuildContext context) {
//----------I add the tags to the list view for the first time-----
var textEditingControllers = <TextEditingController>[];
var textformFields = <Widget>[];
widget.doctags?.forEach((element) {
var textEditingController = new TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
return _addformWidget(textformFields, textEditingController);
//);
});
//------------------------------------------
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
actions: [
IconButton(onPressed: (){
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: Text('Delete TODO'),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Delete'),
onPressed: () {
deleteData(widget.docid.toString(), context);
setState(() {
showSnackBar(context, 'todo "${widget.doctitle}" successfully deleted!');
});
},
),
],
);
},
);
},
icon: Icon(Icons.delete))
],
backgroundColor: Colors.grey[900],
title: Text("${widget.doctitle}"),
),
body: Container(
child: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 10),
TextFormField(
controller: tcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Title",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: dcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Description",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: icontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Image url",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
Row(children: [
Text("Tags:", style:TextStyle(color: Colors.white)),
//-----------------------here I try to add the new text form field-----------
IconButton(onPressed: (){
var textEditingController = new TextEditingController(text: "tag");
textEditingControllers.add(textEditingController);
_addformWidget(textformFields,textEditingController);
print(textformFields.length);
},
icon: Icon(Icons.add,color: Colors.white,),
)
],),//------------------------
/*SingleChildScrollView(
child: new Column(
children: textformFields,
)
),*/
//--------------------------------here I build my list--------------
Expanded(
child: SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context,index) {
return textformFields[index];
}),
)
),
],
),
),
),
),
//--------------------------------------------------
floatingActionButton: FloatingActionButton(
onPressed: (){
if(tcontroller == '' && dcontroller == '' && icontroller == ''){
print("not valid");
}else{
var todo = Todo2(
title: tcontroller.text,
description: dcontroller.text,
image: icontroller.text,
//tags: tagcontroller.text,
);
updateData(todo, widget.docid.toString(),context);
setState(() {
showSnackBar(context, 'todo ${widget.doctitle} successfully updated!');
});
}
},
child: Icon(Icons.update),
),
);
}
}
Any help appreciated!
Since you've kept the list of form fields and controllers in the build function, the widget isn't rebuilt when you call setState on them.
Instead move these to with other state variables.
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
final textEditingControllers = <TextEditingController>[];
final textformFields = <Widget>[];
Now you can change the _addformWidget function to directly use the list without taking it as a parameter.
void _addformWidget(TextEditingController controller) {
setState(() {
textformFields.add(tagForm(controller));
});
}
Then initialise them in the initState function.
#override
void initState() {
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
widget.doctags?.forEach((element) {
final textEditingController = new TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
_addformWidget(textEditingController);
//);
});
}
This ideally should fix your problem. Let me know if it doesn't and if it does, you can click the check mark to confirm that.
//// Remove textEditingControllers and textformFields list from the build. And declare it on top.
#override
Widget build(BuildContext context) {
//----------I add the tags to the list view for the first time-----
var textEditingControllers = <TextEditingController>[];
var textformFields = <Widget>[];
//// Use like below
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
var textEditingControllers = <TextEditingController>[]; //<---------
var textformFields = <Widget>[];
////// Full Code
class TodoEdit extends StatefulWidget {
String? doctitle;
String? doctdescription;
String? docimage;
String? docid;
List? doctags;
TodoEdit(
{Key? key,
this.doctitle,
this.doctdescription,
this.docimage,
this.docid,
this.doctags})
: super(key: key);
#override
_TodoEditState createState() => _TodoEditState();
}
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
var textEditingControllers = <TextEditingController>[];
var textformFields = <Widget>[];
#override
void initState() {
widget.doctags?.forEach((element) {
var textEditingController = TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
return _addformWidget(textformFields, textEditingController);
//);
});
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: Text('Delete TODO'),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Delete'),
onPressed: () {
deleteData(widget.docid.toString(), context);
setState(() {
showSnackBar(context,
'todo "${widget.doctitle}" successfully deleted!');
});
},
),
],
);
},
);
},
icon: Icon(Icons.delete))
],
backgroundColor: Colors.grey[900],
title: Text("${widget.doctitle}"),
),
body: Container(
child: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 10),
TextFormField(
controller: tcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Title",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: dcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Description",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: icontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Image url",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
Row(
children: [
Text("Tags:", style: TextStyle(color: Colors.white)),
//-----------------------here I try to add the new text form field-----------
IconButton(
onPressed: () {
var textEditingController =
new TextEditingController(text: "tag");
textEditingControllers.add(textEditingController);
_addformWidget(textformFields, textEditingController);
print(textformFields.length);
},
icon: Icon(
Icons.add,
color: Colors.white,
),
)
],
), //------------------------
/*SingleChildScrollView(
child: new Column(
children: textformFields,
)
),*/
//--------------------------------here I build my list--------------
Expanded(
child: SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context, index) {
return textformFields[index];
}),
)),
],
),
),
),
),
//--------------------------------------------------
floatingActionButton: FloatingActionButton(
onPressed: () {
if (tcontroller == '' && dcontroller == '' && icontroller == '') {
print("not valid");
} else {
var todo = Todo2(
title: tcontroller.text,
description: dcontroller.text,
image: icontroller.text,
//tags: tagcontroller.text,
);
updateData(todo, widget.docid.toString(), context);
setState(() {
showSnackBar(
context, 'todo ${widget.doctitle} successfully updated!');
});
}
},
child: Icon(Icons.update),
),
);
}
//--------------------add widget to list----------------
void _addformWidget(list, controller) {
setState(() {
list.add(tagForm(controller));
});
}
// -----------------------------my widget------------
Widget tagForm(controller) {
return TextFormField(
controller: controller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Tag",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
);
}
}
I am including an AlertDialog when the app user is not registered in Cloud Firestore:
class MuroScreen extends StatefulWidget {
const MuroScreen({Key? key}) : super(key: key);
#override
_MuroScreenState createState() => _MuroScreenState();
}
class _MuroScreenState extends State<MuroScreen> {
CollectionReference userRef = FirebaseFirestore.instance.collection('clientes');
Future<void> salir() async {
await FirebaseAuth.instance.signOut().catchError((error){
print(error.toString());
});
Navigator.of(context).push(MaterialPageRoute(builder: (c)=>MyHomePage001()),);
}
Future<void> verificarUsuario() async{
DocumentSnapshot snapshotUser = await userRef
.doc(FirebaseAuth.instance.currentUser!.phoneNumber)
.get();
print("existe?"+snapshotUser.exists.toString());
if(snapshotUser.exists){
//ya existe
print("si EXISTE");
}
else {
//no existe
print("no EXISTE");
var nameController = TextEditingController();
Alert(
context: context,
title: "LOGIN",
content: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
icon: Icon(Icons.account_circle),
labelText: 'Username',
),
),
TextField(
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.lock),
labelText: 'Password',
),
),
],
),
buttons: [
DialogButton(
onPressed: () => Navigator.pop(context),
child: Text(
"LOGIN",
style: TextStyle(color: Colors.white, fontSize: 20),
),
)
]).show();
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
verificarUsuario();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(65),
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red,
),
onPressed: () {
salir();
},
child: Text("Logout",style: TextStyle(color:Colors.white,fontSize: 16, fontWeight: FontWeight.bold),),
),
)
],
),
);
}
}
Alert is a rflutter_alert widget.
The issue is that every time I click on a textfield inside the alert widget, the screen reloads and shows the alert again without showing the keyboard, it reloads again.
You are calling the verificarUsuario(); in init() which doesn't have a context. The alert needs a context from build method to show. Please add a button inside the scaffold and open this alert after passing the the context as an argument. It should work.
i am new to flutter. recently building a project of a timer app. ok the homepage is when the user open the app. it will enter a number for hours, minute and second they want to countdown. then this three numbers will be send to another page in a code line here
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: inputdataint),//inputdataint means the constructor i build. don't know correct or not
);
}
so the problem here is when I want to send the three numbers that input by the user and send it to the second screen that is the Countdowntimer screen it gives me an error of the inputdataint isn't defined. but I already defined the inputdataint in the class. can anyone help.
this is the error part
Navigator.push(context,MaterialPageRoute(builder: (context)=>CountDownTimer(inputdataint:hourController.text )));
and this is my whole code. i don't know whether is my code got problem or maybe ...
class inputdatacountdown extends StatefulWidget {
#override
_inputdatacountdownState createState() => _inputdatacountdownState();
}
class _inputdatacountdownState extends State<inputdatacountdown> {
final hourController = TextEditingController();
final minuteController = TextEditingController();
final secondController = TextEditingController();
final _key = GlobalKey<FormState>();
int inputdata;
_inputdatacountdownState(){
inputdata=int.parse(hourController.text);
}
#override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
final nametext =
MediaQuery.of(context).platformBrightness == Brightness.dark
? Colors.white
: Colors.black;
final nametextonbutton =
MediaQuery.of(context).platformBrightness == Brightness.dark
? Colors.black
: Colors.white;
return Scaffold(
body: Center(
child: Container(
child: Form(
key: _key,
child: Column(
children: [
TextFormField(
controller: hourController,
decoration: InputDecoration(
hintText: 'e.g 1',
labelText: 'hours',
border:
OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(Icons.close),
onPressed: () =>
hourController
.clear(),
),
),
keyboardType:
TextInputType.number,
textInputAction:
TextInputAction.done,
validator: (value) {
if (value.isEmpty) {
return 'hours cannot be empty';
} else
return null;
}),
TextFormField(
controller: minuteController,
decoration: InputDecoration(
hintText: 'e.g 1',
labelText: 'minutes',
border:
OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(Icons.close),
onPressed: () =>
minuteController
.clear(),
),
),
keyboardType:
TextInputType.number,
textInputAction:
TextInputAction.done,
validator: (value) {
if (value.isEmpty) {
return 'minutes cannot be empty';
} else
return null;
}),
TextFormField(
controller: secondController,
decoration: InputDecoration(
hintText: 'e.g 1',
labelText: 'second',
border:
OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(Icons.close),
onPressed: () =>
secondController
.clear(),
),
),
keyboardType:
TextInputType.number,
textInputAction:
TextInputAction.done,
validator: (value) {
if (value.isEmpty) {
return 'second cannot be empty';
} else
return null;
}),
FlatButton(
color: nametext,
onPressed: () {
if (_key.currentState
.validate()) {
print(
'hour: ${hourController.text}');
print(
'minutes: ${minuteController.text}');
print(
'second: ${secondController.text}');
Navigator.push(context,MaterialPageRoute(builder: (context)=>CountDownTimer(inputdataint:hourController.text )));
}
},
child: Text(
'submit ',
style: TextStyle(
color:
nametextonbutton),
))
],
)),
),
),
);
}
}
class CountDownTimer extends StatefulWidget {
#override
_CountDownTimerState createState() => _CountDownTimerState();
}
class _CountDownTimerState extends State<CountDownTimer>
with TickerProviderStateMixin {
AnimationController controller;
String get timerString {
Duration duration = controller.duration * controller.value;
return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
}
int inputdataint;
CountDownTimer(int inputdataint){
this.inputdataint = inputdataint;
}
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: inputdataint),//come back to you later
);
}
#override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
final nametext =
MediaQuery.of(context).platformBrightness == Brightness.dark
? Colors.white
: Colors.black;
final nametextonbutton =
MediaQuery.of(context).platformBrightness == Brightness.dark
? Colors.black
: Colors.white;
return Scaffold(
backgroundColor: Colors.white10,
body: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: FractionalOffset.center,
child: AspectRatio(
aspectRatio: 1.0,
child: Stack(
children: <Widget>[
Positioned.fill(
child: CustomPaint(
painter: CustomTimerPainter(
animation: controller,
backgroundColor: Colors.white,
color: themeData.indicatorColor,
)),
),
Align(
alignment: FractionalOffset.center,
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Text(
"Count Down Timer",
style: TextStyle(
fontSize: 20.0, color: nametext),
),
Text(
timerString,
style: TextStyle(
fontSize: 112.0, color: nametext),
),
],
),
),
],
),
),
),
),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return FloatingActionButton.extended(
onPressed: () {
if (controller.isAnimating)
controller.stop();
else {
controller.reverse(
from: controller.value == 0.0
? 1.0
: controller.value);
}
},
icon: Icon(controller.isAnimating
? Icons.pause
: Icons.play_arrow),
label: Text(
controller.isAnimating ? "Pause" : "Play"));
}),
],
))
]);
}),
);
}
}
What's happening there is that you send an argument named inputdataint to your Widget CountDownTimer by doing so:
Navigator.push(context,MaterialPageRoute(builder: (context)=>CountDownTimer(inputdataint:hourController.text )));
You can see there that you send the value hourController.text to the CountDownTimer as an argument called inputdataint.
The error came from the definition of your CountDownTimer widget definition.
You didn't declare the argument inputdataint but you are trying to use this value.
For doing so, you need to update your code like so:
class CountDownTimer extends StatefulWidget {
final String inputdataint;
const CountDownTimer({this.inputdataint});
#override
_CountDownTimerState createState() => _CountDownTimerState();
}
class _CountDownTimerState extends State<CountDownTimer>
with TickerProviderStateMixin {
// Your widget there...
// Use widget.inputdataint to use the data your passed to this widget.
}