So i got an error said that "The argument type 'Map<String, Object>' can't be assigned to the parameter type 'Iterable<Map<String, dynamic>>" which im trying to pass my textfield data into the list. The problem is at the function call void addItemtoList() can anyone help me with this problem heres the code
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:intl/intl.dart';
import 'contactDetail.dart';
class ContactList extends StatefulWidget {
const ContactList({Key? key}) : super(key: key);
#override
State<ContactList> createState() => _ContactListState();
}
class _ContactListState extends State<ContactList> {
final dateStr = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now());
final List<Map<String, dynamic>> _allUsers = [
{"id": 1, "name": "Andy", "age": "29"},
{"id": 2, "name": "Aragon", "age": "40"},
];
TextEditingController nameController = TextEditingController();
TextEditingController phoneController = TextEditingController();
void addItemToList() {
setState(() {
_allUsers.addAll({
"id":1,
"name":nameController.text,
"age":phoneController.text}
);
});
}
// This list holds the data for the list view
List<Map<String, dynamic>> _foundUsers = [];
#override
initState() {
_foundUsers = _allUsers;
super.initState();
}
// This function is called whenever the text field changes
void _runFilter(String enteredKeyword) {
List<Map<String, dynamic>> results = [];
if (enteredKeyword.isEmpty) {
// if the search field is empty or only contains white-space, we'll display all users
results = _allUsers;
} else {
results = _allUsers
.where((user) =>
user["name"].toLowerCase().contains(enteredKeyword.toLowerCase()))
.toList();
// we use the toLowerCase() method to make it case-insensitive
}
setState((){
_foundUsers = results;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Search Listview'),
),
body: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: [
const SizedBox(
height: 20,
),
TextField(
controller: nameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Name',
),
),
const SizedBox(height: 20,),
TextField(
controller: phoneController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Phone',
),
),
const SizedBox(height: 20,),
TextField(
onChanged: (value) => _runFilter(value),
decoration: const InputDecoration(
labelText: 'Search', suffixIcon: Icon(Icons.search)),
),
const SizedBox(height: 20,),
Expanded(
child: _foundUsers.isNotEmpty
? ListView.builder(
itemCount: _foundUsers.length,
itemBuilder: (context, index) => Card(
key: ValueKey(_foundUsers[index]["id"]),
color: Colors.blue,
elevation: 4,
margin: const EdgeInsets.symmetric(vertical: 10),
child: ListTile(
leading: Text(
_foundUsers[index]["id"].toString(),
style: const TextStyle(fontSize: 24, color:Colors.white),
),
title: Text(_foundUsers[index]['name'], style:TextStyle(
color:Colors.white
)),
subtitle: Text(
'${_foundUsers[index]["age"].toString()} years old',style:TextStyle(
color:Colors.white
)),
),
),
)
: const Text(
'No results found',
style: TextStyle(fontSize: 24),
),
),
],
),
),
);
}
}
Instead of call addAll use add:
_allUsers.add({
"id":1,
"name":nameController.text,
"age":phoneController.text}
);
addAll used when you want add list of something.
Related
I'm a total beginner in Flutter. I try to integrate a textfield filter for my table, but the table is not filtered, but remains unchanged. I added a Provider because I need the current table of Students. after that the Table can't be filtered anymore. Can anyone help me?
here is my code:
class ResultPage extends StatefulWidget {
const ResultPage({Key? key}) : super(key: key);
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
List<User>? myData = [];
List<User>? filterData;
_getData(BuildContext context){
myData = Provider.of<LoginService>(context).getStudentsList();
filterData = Provider.of<LoginService>(context).getStudentsList();
}
bool sort = true;
#override
void initState() {
filterData = myData;
super.initState();
}
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
_getData(context);
return Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: Theme(
data: ThemeData.light()
.copyWith(cardColor: Theme.of(context).canvasColor),
child: PaginatedDataTable(
sortColumnIndex: 0,
sortAscending: sort,
header: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.circular(12)),
child: TextField(
controller: controller,
decoration: const InputDecoration(
hintText: "Enter name to filter"),
onChanged: (value) {
setState(() {
myData = filterData!
.where(
(element) => element.getName.contains(value))
.toList();
});
},
onSubmitted: (value) {
setState(() {
FocusScope.of(context).unfocus();
});
},
),
),
source: RowSource(
myData: myData,
count: myData!.length,
),
rowsPerPage: 16,
columnSpacing: 8,
columns: const [
DataColumn(
label: Text(
"Schüler",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
DataColumn(
label: Text(
"Anzahl Spiele",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
DataColumn(
label: Text(
"Score",
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 14),
),
),
],
),
)),
const SizedBox(height: 20),
],
),
)
);
}
}
class RowSource extends DataTableSource {
var myData;
final count;
RowSource({
required this.myData,
required this.count,
});
#override
DataRow? getRow(int index) {
if (index < rowCount) {
return recentFileDataRow(myData![index]);
} else {
return null;
}
}
#override
bool get isRowCountApproximate => false;
#override
int get rowCount => count;
#override
int get selectedRowCount => 0;
}
DataRow recentFileDataRow(User data) {
return DataRow(
cells: [
DataCell(Text(data.getName)),
DataCell(Text(data.getSolvedGames().toString())),
DataCell(Text(data.getScore().toString())),
],
);
}
With my code the table always remains unchanged.
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;
},
),
],
),
);
}
}
I'm emulating this search and filter github here and the codes are almost the same but the filtered results do not update instantly while I type and also I faced the following issues:
I will have to press enter on my laptop to finally get the filtered list
When I hit the close icon(which is to clear all the words), I will have to tap the searchbar again so that all my listtile are back on the listview.
Here's my code:
class _CurrencySelectState extends State<CurrencySelect> {
late List<Currency> resCur;
String query = '';
#override
void initState() {
super.initState();
resCur = currencyList;
}
void searchCur(String query) {
final List<Currency> filteredCur = currencyList.where((cur) {
final symbolLower = cur.symbol.toLowerCase(); // Search using symbol
final nameLower = cur.country.toLowerCase(); // Search using country
final searchLower = query.toLowerCase();
return symbolLower.contains(searchLower) ||
nameLower.contains(searchLower);
}).toList();
setState(() {
this.query = query;
resCur = filteredCur;
});
}
#override
Widget build(BuildContext context) {
Widget buildCur(Currency cur) => ListTile(
leading: Padding(
padding: EdgeInset.all(5)
child: SizedBox(
child: Column(
children: <Widget>[
SvgPicture.asset(
cur.assetPath,
),
]),
),
),
title: Column(
children: [
Text(
cur.symbol,
style: TextStyle(
...
),
Text(
cur.name,
style: TextStyle(
...
),
],
),
trailing: Text(
"0.25",
style: TextStyle(
...
),
);
return TextButton(
onPressed: () async {
showModalBottomSheet(
enableDrag: false,
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return DraggableScrollableSheet(
expand: false,
builder: (context, scrollController) {
return Column(
children: <Widget>[
SearchWidget(
text: query,
onChanged: searchCur,
hintText: "Enter symbol or country"
),
Expanded(
child: ListView.builder(
controller: scrollController,
itemCount: resCur.length,
itemBuilder: (context, int index) {
final cur = resCur[index];
return buildCur(cur);
},
),
)
],
);
},
);
});
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
...
),
SvgPicture.asset(
...
)
],
));
}
}
Searchwidget code:
import 'package:flutter/material.dart';
class SearchWidget extends StatefulWidget {
final String text;
final ValueChanged<String> onChanged;
final String hintText;
const SearchWidget({
Key? key,
required this.text,
required this.onChanged,
required this.hintText,
}) : super(key: key);
#override
_SearchWidgetState createState() => _SearchWidgetState();
}
class _SearchWidgetState extends State<SearchWidget> {
final controller = TextEditingController();
#override
Widget build(BuildContext context) {
final styleActive = TextStyle(color: Colors.black);
final styleHint = TextStyle(color: Colors.black54);
final style = widget.text.isEmpty ? styleHint : styleActive;
return Container(
height: 42,
margin: const EdgeInsets.fromLTRB(16, 16, 16, 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
border: Border.all(color: Colors.black26),
),
padding: const EdgeInsets.symmetric(horizontal: 8),
child: TextField(
controller: controller,
decoration: InputDecoration(
icon: Icon(Icons.search, color: style.color),
suffixIcon: widget.text.isNotEmpty
? GestureDetector(
child: Icon(Icons.close, color: style.color),
onTap: () {
controller.clear();
widget.onChanged('');
FocusScope.of(context).requestFocus(FocusNode());
},
)
: null,
hintText: widget.hintText,
hintStyle: style,
border: InputBorder.none,
),
style: style,
onChanged: widget.onChanged,
),
);
}
}
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,
),
);
}
}
Hy, im working on a project, using table_calendar plugin im receiving meetings record from database and showing them as a marker on the calendar, now i want to show that meeting details on the page in a list, but i don't have any idea how to do that, i able to print it meeting ids in the list, but how i can print other meetings details also, like location, time, customer name etc?
import 'package:flutter/material.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:intl/intl.dart';
import 'notifcation_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:table_calendar/table_calendar.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'variables.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:expandable/expandable.dart';
TextEditingController agendaController = new TextEditingController();
TextEditingController phoneController = new TextEditingController();
TextEditingController locationController = new TextEditingController();
meeting mee = new meeting();
meeting meet = new meeting();
String _time = '';
List meetDate;
CalendarController _controller;
String dateWithT;
String emailFromSharedPref, meetingAdded;
Map smData;
Map meetingDetail;
List meetingInfo, customerInfo;
List<dynamic> _selectedEvents;
Map<DateTime, List<dynamic>> _events;
Map<DateTime, List<dynamic>> c_nameMap;
class AddMeeting extends StatefulWidget {
#override
_AddMeetingeState createState() => _AddMeetingeState();
}
class _AddMeetingeState extends State<AddMeeting> {
#override
void initState() {
super.initState();
_controller = CalendarController();
_events = {};
_selectedEvents = [];
c_nameMap = {};
getIdAndGetMeetings();
}
Future getIdAndGetMeetings() async {
// getting email from SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
emailFromSharedPref = prefs.getString('email');
// getting saleManager info using email
var url = "http://.../getSaleMangerDetal.php";
var response = await http.post(url, body: {
"m_email": emailFromSharedPref,
});
smData = jsonDecode(response.body);
// getting customer info using saleManagerID
var customerInfoUrl = "http://.../calender/getCustomerInfo.php";
var customerInfoResponse = await http.post(customerInfoUrl, body: {
"sm_id": smData['manager_id'],
});
// saving customer info in the list, because there are many dict in the list
customerInfo = jsonDecode(customerInfoResponse.body);
// get meetings details from server using saleManager Id
var getmeetingUrl = "http://.../getMeetings.php";
var getMeetiongResponse = await http.post(getmeetingUrl, body: {
"manager_id": smData['manager_id'],
});
meetingInfo = jsonDecode(getMeetiongResponse.body);
print(meetingInfo);
for (int i = 0; i < meetingInfo.length; i++) {
dateWithT =
meetingInfo[i]['m_date'].replaceAll(new RegExp(r'[^\w\s]+'), '');
dateWithT = dateWithT.replaceAll(' ', '');
dateWithT = dateWithT + "000000";
dateWithT = dateWithT.substring(0, 8) + 'T' + dateWithT.substring(8);
mee.dateTime = DateTime.parse(dateWithT);
if (_events[mee.dateTime] != null) {
_events[mee.dateTime].add(meetingInfo[i]['meeting_id']);
} else {
_events[mee.dateTime] = [meetingInfo[i]['meeting_id']];
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Calendar'),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Text(_time),
TableCalendar(
events: _events,
// initialCalendarFormat: CalendarFormat.week,
calendarStyle: CalendarStyle(
canEventMarkersOverflow: true,
todayColor: Colors.orange,
selectedColor: Theme.of(context).primaryColor,
todayStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white)),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonDecoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(20.0),
),
formatButtonTextStyle: TextStyle(color: Colors.white),
formatButtonShowsNext: false,
),
startingDayOfWeek: StartingDayOfWeek.monday,
onDaySelected: (date, events) {
setState(() {
_selectedEvents = events;
});
},
builders: CalendarBuilders(
calendarController: _controller,
),
..._selectedEvents.map((event) => Stack(
children: <Widget>[
// getMeetingsIndividualDetails(event),
Card(
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ExpandablePanel(
header: Text(event),
// Text(getMeetingsIndividualDetails(event, 'c_name')),
collapsed: Text(
'qwe',
softWrap: true,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
expanded: Text(
'as',
softWrap: true,
),
tapHeaderToExpand: true,
hasIcon: true,
),
),
),
),
],
)),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _showAddDialog,
),
);
}
_showAddDialog() async {
await showDialog(
context: context,
builder: (context) => StatefulBuilder(builder: (context, setState) {
return ShowDialog();
}));
setState(() {
_selectedEvents = _events[mee.dateTime];
});
}
}
addMeetingToDatabase(List meetDate2) async {
// print(meetDate2[0]);
var getmeetingUrls = "http://.../addMeeting.php";
var getMeetiongResponses = await http.post(getmeetingUrls, body: {
"sm_id": smData['manager_id'],
"c_id": '2',
"agenda": agendaController.text,
"phone": phoneController.text,
"location": locationController.text,
"date": meetDate2[0],
"time": _time,
});
meetingAdded = jsonDecode(getMeetiongResponses.body);
print(meetingAdded);
}
class ShowDialog extends StatefulWidget {
#override
_ShowDialogState createState() => _ShowDialogState();
}
class _ShowDialogState extends State<ShowDialog> {
#override
Widget build(BuildContext context) {
return AlertDialog(
content: SingleChildScrollView(
child: Container(
// height: MediaQuery.of(context).size.height/3,
child: Column(
// mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: TextField(
controller: phoneController,
// maxLines: null,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Phone',
prefixIcon: Icon(Icons.phone_android),
labelStyle: TextStyle(fontSize: 15)),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: TextField(
controller: locationController,
// maxLines: null,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Meeting Location',
prefixIcon: Icon(Icons.add_location),
labelStyle: TextStyle(fontSize: 15)),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RaisedButton(
child: Text('Meeting Time'),
onPressed: () {
DatePicker.showTimePicker(context,
theme: DatePickerTheme(
containerHeight: 210.0,
),
showTitleActions: true, onConfirm: (time) {
print('confirm $time');
_time =
'${time.hour} : ${time.minute} : ${time.second}';
setState(() {});
},
currentTime: DateTime.now(),
locale: LocaleType.en);
setState(() {});
}),
Text(_time)
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: TextField(
controller: agendaController,
maxLines: null,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Agenda',
prefixIcon: Icon(Icons.message),
labelStyle: TextStyle(fontSize: 15)),
),
),
],
),
),
),
actions: <Widget>[
FlatButton(
child: Text("Save"),
onPressed: () {
// if (agendaController.text.isEmpty) return;
// if (_events[_controller.selectedDay] != null) {
// _events[_controller.selectedDay]
// .add(agendaController.text);
String asd = _controller.selectedDay.toString();
meetDate = asd.split(' ');
addMeetingToDatabase(meetDate);
agendaController.clear();
phoneController.clear();
locationController.clear();
Navigator.pop(context);
},
)
],
);
}
}
what i have achieved?
What i want to achieve
Instead of List<Dynamic>, it's better to map those data on an object so it can be accessed with a constant getter function.
Let Map<DateTime, List<dynamic>> _events; be Map<DateTime, EventDetails> _events;
where EventDetails contains for example:
class EventDetails {
String author;
String eventName;
String description;
EventDetails(
{required this.author,
required this.eventName,
required this.description});
}
Then you can add data using an Object.
EventDetails eventDetails = EventDetails(author: 'AUTHOR',
eventName: 'EVENT_NAME', description: 'DESCRIPTION');
...
_events[mee.dateTime].add(eventDetails);