Related
What im trying to do is showing a list of assignments and have buttons at the bottom to let the user to select which function they want but when the data becomes a lot and my buttons got push below the screen, i was hoping for the buttons to stay on the screen no matter how many data is generated, buttons will not get push down and the button does not block the visuals of the data, i got an image below to show that
example at here
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fyp/assignment/ViewComplete.dart';
import 'ReassignEmployee.dart';
import 'ViewAssigned.dart';
import 'ViewUnassigned.dart';
class assignmentPage extends StatefulWidget {
const assignmentPage({Key? key}) : super(key: key);
#override
State<assignmentPage> createState() => _assignmentPageState();
}
class _assignmentPageState extends State<assignmentPage> {
TextEditingController searchController = TextEditingController();
String searchText = '';
String id = '';
CollectionReference allNoteCollection =
FirebaseFirestore.instance.collection('Assignment');
List<DocumentSnapshot> documents = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('View Assignment'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: searchController,
onChanged: (value) {
setState(() {
searchText = value;
});
},
decoration: InputDecoration(
hintText: 'Search...',
prefixIcon: Icon(Icons.search),
),
),
StreamBuilder(
stream: allNoteCollection.snapshots(),
builder: (ctx, streamSnapshot) {
if (streamSnapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator());
}
documents = streamSnapshot.data!.docs;
if (searchText.length > 0) {
documents = documents.where((element)
{
return
( element.get('carPlate').toString().
toLowerCase().contains(searchText.toLowerCase()) ||
element.get('custName').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('date').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('employee').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('id').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('payment').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('serviceName').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('status').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('timeEnd').toString().
toLowerCase().contains(searchText.toLowerCase())||
element.get('timeStart').toString().
toLowerCase().contains(searchText.toLowerCase())
);
}).toList();
}
return ListView.separated(
reverse: true,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: documents.length,
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
itemBuilder: (BuildContext context, int index) {
id = documents[index]['id'];
return ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 0.0),
onTap: () {
},
title: Column(
children: <Widget>[
Text(documents[index]['carPlate']),
Text(documents[index]['custName']),
Text(documents[index]['date']),
Text(documents[index]['employee']),
Text(documents[index]['payment']),
Text(documents[index]['serviceName']),
Text(documents[index]['status']),
Text(documents[index]['timeStart']),
Text(documents[index]['timeEnd']),
],
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
onTap: (){
Navigator.push(context,
MaterialPageRoute(builder: (context) => ReassignEmployee(
serviceName: documents[index]['serviceName'],
carPlate: documents[index]['carPlate'],
custName: documents[index]['custName'],
date: documents[index]['date'],
timeStart: documents[index]['timeStart'],
timeEnd: documents[index]['timeEnd'],
payment: documents[index]['payment'],
status: documents[index]['status'],
employee: documents[index]['employee'],
id: documents[index]['id'],
)));
},child: Icon(Icons.edit),
),
],
)
);
},
);
},
),
ElevatedButton(
onPressed: () async {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ViewUnassigned(id: id.toString(),)));
},
child: Text('Show unassigned'),
),
ElevatedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ViewAssigned()));
},
child: Text('Show assigned'),
),
],
),
),
);
}
}
I have no idea how to do it, hope someone can guide me, really thanks a lot
You can use Stack and Positioned to pin buttons to the bottom of screen, like this:
class assignmentPage extends StatefulWidget {
const assignmentPage({Key? key}) : super(key: key);
#override
State<assignmentPage> createState() => _assignmentPageState();
}
class _assignmentPageState extends State<assignmentPage> {
TextEditingController searchController = TextEditingController();
String searchText = '';
String id = '';
CollectionReference allNoteCollection =
FirebaseFirestore.instance.collection('Assignment');
List<DocumentSnapshot> documents = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('View Assignment'),
),
body: Stack(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: searchController,
onChanged: (value) {
setState(() {
searchText = value;
});
},
decoration: InputDecoration(
hintText: 'Search...',
prefixIcon: Icon(Icons.search),
),
),
StreamBuilder(
stream: allNoteCollection.snapshots(),
builder: (ctx, streamSnapshot) {
if (streamSnapshot.connectionState ==
ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
documents = streamSnapshot.data!.docs;
if (searchText.length > 0) {
documents = documents.where((element) {
return (element
.get('carPlate')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('custName')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('date')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('employee')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('id')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('payment')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('serviceName')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('status')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('timeEnd')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()) ||
element
.get('timeStart')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase()));
}).toList();
}
return ListView.separated(
reverse: true,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: documents.length,
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
itemBuilder: (BuildContext context, int index) {
id = documents[index]['id'];
return ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 0.0),
onTap: () {},
title: Column(
children: <Widget>[
Text(documents[index]['carPlate']),
Text(documents[index]['custName']),
Text(documents[index]['date']),
Text(documents[index]['employee']),
Text(documents[index]['payment']),
Text(documents[index]['serviceName']),
Text(documents[index]['status']),
Text(documents[index]['timeStart']),
Text(documents[index]['timeEnd']),
],
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ReassignEmployee(
serviceName: documents[index]
['serviceName'],
carPlate: documents[index]
['carPlate'],
custName: documents[index]
['custName'],
date: documents[index]
['date'],
timeStart: documents[index]
['timeStart'],
timeEnd: documents[index]
['timeEnd'],
payment: documents[index]
['payment'],
status: documents[index]
['status'],
employee: documents[index]
['employee'],
id: documents[index]['id'],
)));
},
child: Icon(Icons.edit),
),
],
));
},
);
},
),
],
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Column(
children: [
ElevatedButton(
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ViewUnassigned(
id: id.toString(),
)));
},
child: Text('Show unassigned'),
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ViewAssigned()));
},
child: Text('Show assigned'),
),
],
))
],
),
);
}
}
I am trying to toggle between Login Screen and HomeScreen based on the user status. The logic seems to be working as long as I don't put HomeScreen.
I replaced HomeScreen with a different screen to check and the app works as it should. It displays different screens on hot restart based on the user's login status. But as soon as I try to put HomeScreen I get null operator used on null value error.
Here is the toggle logic.
class Testing extends StatefulWidget {
const Testing({super.key});
#override
State<Testing> createState() => _TestingState();
}
class _TestingState extends State<Testing> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: TodoServiceHelper().checkifLoggedIn(),
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.hasError) {
print(snapshot.hasError);
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.data!.isNotEmpty) {
print(snapshot.data);
return RegisterPage();
// returning HomePage gives null check operator used on null value error
} else
return Login();
}),
);
}
}
Here is the HomeScreen
class HomePage extends StatefulWidget {
String? username;
HomePage({this.username});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final GlobalKey<FormState> formKey = GlobalKey();
TextEditingController termController = TextEditingController();
void clearText() {
termController.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
User loginUser =
User(username: widget.username.toString(), isLoggedIn: false);
TodoServiceHelper().updateUserName(loginUser);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Login()));
},
icon: Icon(Icons.logout),
color: Colors.white,
)
],
title: FutureBuilder(
future: TodoServiceHelper().getTheUser(widget.username!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
return Text(
'Welcome ${snapshot.data!.username}',
style: TextStyle(color: Colors.white),
);
}),
),
body: SingleChildScrollView(
child: Column(children: [
Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: termController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(),
labelText: 'search todos',
),
),
TextButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShowingSerachedTitle(
userNamee: widget.username!,
searchTerm: termController.text,
)),
);
print(termController.text);
clearText();
setState(() {});
},
child: Text(
'Search',
)),
Divider(
thickness: 3,
),
],
),
),
),
],
),
Container(
child: Stack(children: [
Positioned(
bottom: 0,
child: Text(
' done Todos',
style: TextStyle(fontSize: 12),
),
),
IconButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CheckingStuff(userNamee: widget.username!)),
);
setState(() {});
},
icon: Icon(Icons.filter),
),
]),
),
Divider(
thickness: 3,
),
Container(
child: TodoListWidget(name: widget.username!),
height: 1000,
width: 380,
)
]),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color.fromARGB(255, 255, 132, 0),
onPressed: () async {
await showDialog(
barrierDismissible: false,
context: context,
builder: ((context) {
return AddNewTodoDialogue(name: widget.username!);
}),
);
setState(() {});
},
child: Icon(Icons.add),
),
);
}
}
The function used to return user with loginStatus true
Future<List<User>> checkifLoggedIn() async {
final Database db = await initializeDB();
final List<Map<String, Object?>> result = await db.query(
'users',
where: 'isLoggedIn = ?',
whereArgs: ['1'],
);
List<User> filtered = [];
for (var item in result) {
filtered.add(User.fromMap(item));
}
return filtered;
}
the problem is here
you used ! sign on a nullable String , and this string is nullable,
try to use this operation (??) so make it
widget.username??"" by this line you will check if the user name is null it will be replaced by an empty string.
I am getting an error and red screen while trying to click a button. RangeError (index): Invalid value: Valid value range is empty: 0. I do not know how to fix this error because nothing is flagged until I run my emulator. I have attached my
If I need to add some code please let me know I am more than willing to. Thank you!
home_page.dart
import 'package:flutter/material.dart';
import 'package:timestudy_test/pages/study_page.dart';
import 'package:timestudy_test/pages/timer_page.dart';
import 'package:timestudy_test/viewmodels/study_viewmodel.dart';
class HomePage extends StatefulWidget {
#override
State createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
TextEditingController textController = new TextEditingController();
late String filter;
#override
void initState() {
textController.addListener(() {
setState(() {
filter = textController.text;
});
});
super.initState();
}
#override
void dispose() {
textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text('TimeStudyApp'),
),
body: Material(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 8.0, left: 16.0, right: 16.0),
child: TextField(
style: TextStyle(fontSize: 18.0),
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
suffixIcon: IconButton(
icon: Icon(Icons.close),
onPressed: () {
textController.clear();
FocusScope.of(context).requestFocus(FocusNode());
},
),
hintText: "Search...",
),
controller: textController,
)),
Expanded(
child: StudyViewModel.studies.length > 0
? ListView.builder(
itemCount: StudyViewModel.studies.length,
itemBuilder: (BuildContext context, int index) {
if (filter == null || filter == "") {
return buildRow(context, index);
} else {
if (StudyViewModel.studies[index].name
.toLowerCase()
.contains(filter.toLowerCase())) {
return buildRow(context, index);
} else {
return Container();
}
}
},
)
: Center(
child: Text('No studies found!'),
),
)
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () async {
int? nullableInterger;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StudyPage(
title: 'Add a study',
selected: nullableInterger ?? 0,
)));
},
),
);
}
Widget buildRow(BuildContext context, int index) {
return ExpansionTile(
title: Text(StudyViewModel.studies[index].name, style: TextStyle(fontSize: 18.0)),
children: <Widget>[
ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: StudyViewModel.studies[index].tasks.length,
itemBuilder: (context, int taskIndex) {
return ListTile(
title: Text(StudyViewModel.studies[index].tasks[taskIndex].name),
contentPadding: EdgeInsets.symmetric(horizontal: 32.0),
subtitle: Text(
StudyViewModel.studies[index].tasks[taskIndex].elapsedTime),
trailing: IconButton(
icon: Icon(
Icons.timer
),
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TimerPage(
task: StudyViewModel
.studies[index].tasks[taskIndex])));
},
),
);
},
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(
Icons.edit
),
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StudyPage(
title: StudyViewModel.studies[index].name,
selected: index)));
},
),
IconButton(
icon: Icon(
Icons.delete
),
onPressed: () async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text('Do you wish to delete this study?'),
actions: <Widget>[
FlatButton(
child: Text('Accept'),
onPressed: () async {
StudyViewModel.studies.removeAt(index);
await StudyViewModel.saveFile();
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
},
),
],
),
],
);
}
}
study_page.dart
import 'package:flutter/material.dart';
import 'package:timestudy_test/models/study.dart';
import 'package:timestudy_test/models/task.dart';
import 'package:timestudy_test/viewmodels/study_viewmodel.dart';
class StudyPage extends StatefulWidget {
final String title;
final int selected;
StudyPage({required this.title, required this.selected});
#override
State createState() => StudyPageState();
}
class StudyPageState extends State<StudyPage> {
late Study study;
late TextField nameField;
TextEditingController nameController = new TextEditingController();
late TextField taskNameField;
TextEditingController taskNameController = new TextEditingController();
#override
void initState() {
nameField = new TextField(
controller: nameController,
decoration: InputDecoration(
labelText: 'Study name'),
);
taskNameField = new TextField(
controller: taskNameController,
decoration:
InputDecoration(labelText: 'Task name'),
);
if(widget.selected != null) {
study = StudyViewModel.studies[widget.selected];
nameController.text = study.name;
} else {
study = new Study(
name: "",
tasks: <Task>[]
);
}
super.initState();
}
#override
void dispose() {
nameController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: Material(
child: Padding(padding: EdgeInsets.all(16.0), child: Column(
children: <Widget>[
Padding(padding: EdgeInsets.only(bottom: 8.0), child: nameField),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Tasks:', style: TextStyle(fontSize: 18.0),),
IconButton(
icon: Icon(Icons.add),
onPressed: () async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add a task'),
content: taskNameField,
actions: <Widget>[
FlatButton(
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('Accept'),
onPressed: () {
if(taskNameController.text == ""){
errorDialog(context, 'Please enter a task name!');
} else {
setState(() {
study.tasks.add(new Task(
name: taskNameController.text,
elapsedTime:
StudyViewModel.milliToElapsedString(
0)));
taskNameController.clear();
});
Navigator.of(context).pop();
}
},
),
],
);
});
},
)
],
),
Expanded(
child: ListView.builder(
itemCount: study.tasks.length,
itemBuilder: (context, int index) {
return ListTile(
title: Text(study.tasks[index].name),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
study.tasks.removeAt(index);
});
},
),
);
},
),
), Spacer(),
Center(
child: RaisedButton(
color: Theme.of(context).accentColor,
child: Text('Save'),
onPressed: () async {
if (nameController.text == "") {
errorDialog(context, 'Please enter a study name!');
} else {
if (study.tasks.length < 1) {
errorDialog(context, 'Please add at least one task!');
} else {
study.name = nameController.text;
if (widget.selected != null) {
StudyViewModel.studies[widget.selected] = study;
await StudyViewModel.saveFile();
Navigator.of(context).pop();
} else {
if (StudyViewModel.checkName(nameController.text)) {
errorDialog(context, 'Study name already taken!');
} else {
StudyViewModel.studies.add(study);
await StudyViewModel.saveFile();
Navigator.of(context).pop();
}
}
}
}
},
))
],
),
)));
}
void errorDialog(BuildContext context, String message) async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(message),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
}
);
}
}
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () async {
int? nullableInterger;
// the issue is here you need to assign value
// the nullableInterger is use here as nothing.. declare it on state level and
// assign it when your listview builder done so the value of nullable integer is
// changed and passing value as argument will not be 0 and this error will not appear again
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StudyPage(
title: 'Add a study',
selected: nullableInterger ?? 0,
)));
},
),
have a to do app which lists all todos in in a screen
This is my listview
class assignedTask extends StatefulWidget {
static const String id = 'assignedTask';
#override
_assignedTaskState createState() => _assignedTaskState();
}
class _assignedTaskState extends State<assignedTask> {
String Title;
String Summary;
var tasks;
crudMedthods crudObj = new crudMedthods();
var documentID;
var documents;
Future<bool> addDialog(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Add Data', style: TextStyle(fontSize: 15.0)),
content: Container(
height: 125.0,
width: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'Enter Title'),
onChanged: (value) {
this.Title = value;
},
),
SizedBox(height: 5.0),
TextField(
decoration: InputDecoration(hintText: 'Enter Summary'),
onChanged: (value) {
this.Summary = value;
},
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Add'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
crudObj.addData({
'Title': this.Title,
'Summary': this.Summary
}).then((result) {
dialogTrigger(context);
}).catchError((e) {
print(e);
});
},
)
],
);
});
}
Future<bool> updateDialog(BuildContext context, selectedDoc) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Update Data', style: TextStyle(fontSize: 15.0)),
content: Container(
height: 125.0,
width: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'Title'),
onChanged: (value) {
this.Title = value;
},
),
SizedBox(height: 5.0),
TextField(
decoration: InputDecoration(hintText: 'Enter Summary'),
onChanged: (value) {
this.Summary = value;
},
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Update'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
crudObj.updateData(selectedDoc, {
'Title': this.Title,
'Summary': this.Summary
}).then((result) {
// dialogTrigger(context);
}).catchError((e) {
print(e);
});
},
)
],
);
});
}
Future<bool> dialogTrigger(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Job Done', style: TextStyle(fontSize: 15.0)),
content: Text('Added'),
actions: <Widget>[
FlatButton(
child: Text('Alright'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
#override
void initState() {
crudObj.getData().then((results) {
setState(() {
tasks = results;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Assigned Tasks'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
addDialog(context);
},
),
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
crudObj.getData().then((results) {
setState(() {
tasks = results;
});
});
},
)
],
),
body: _TaskList(),
);
}
Widget _TaskList() {
if (tasks != null) {
return StreamBuilder(
stream: tasks,
// ignore: missing_return
builder: (context, snapshot) {
if (snapshot.data != null) {
return ListView.builder(
itemCount: snapshot.data.documents.length,
padding: EdgeInsets.all(7.0),
itemBuilder: (context, i) {
return ListTile(
title: Text(snapshot.data.documents[i].data["Title"]??""),
subtitle: Text(snapshot.data.documents[i].data["Summary"]??""),
/*onTap: () {
*//*
updateDialog(
context, snapshot.data.documents[i].documentID);
},*/
onTap: (){
Navigator.push(context,MaterialPageRoute(builder:(context)=>detailview(context,snapshot.data.douments[i].documentid)));
},
onLongPress: () {
crudObj.deleteData(snapshot.data.documents[i].documentID);
},
);
},
);
}
return CircularProgressIndicator();
},
);
} else {
return Text('Loading, Please wait..');
}
}
}
When i press ontap it should go to the detail page which shows details of only that particular task(note: i now have only the values Title and summary for now, i will add rest later they should show in the detail page)
My detailview is as follows
class detailview extends StatefulWidget {
static const String id = 'detailview';
detailview(BuildContext context, selectedDoc);
#override
_detailviewState createState() => _detailviewState();
}
class _detailviewState extends State<detailview> {
final TaskReference = FirebaseDatabase.instance.reference().child('Task');
crudMedthods crudObj1 = new crudMedthods();
/*TextEditingController _titleController;
TextEditingController _descriptionController;*/
var tasks;
/*#override
void initState() {
super.initState();
//_titleController = new TextEditingController(text: widget.tasks.Title);
//_descriptionController = new TextEditingController(text: widget.tasks.Summary);
}*
*/
#override
void initState() {
crudObj1.getDetail(tasks).then((results) {
setState(() {
tasks = results;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Details of Tasks'),
actions: <Widget>[
],
),
body: Column(
children: <Widget>[
TextField(
//controller: _titleController,
),
],
)
);
}
}
How could i access the values of particular tapped value in detail page.
Just pass the DocumentSnapshot to your detail page like this:
onTap: (){
Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailPage(context,snapshot.data.douments[i])));
},
In your detail page receive the DocumentSnapshot and access anything you are getting from it.
class DetailPage extends StatelessWidget {
DocumentSnapshot detailDocument;
DetailPage(this.detailDocument);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(detailDocument.data["Title"]),
),
body: Center(
child: Text(detailDocument.data["Summary"]),
),
);
}
}
I have a to do app which lists all todos in in a screen
This is my listview
class assignedTask extends StatefulWidget {
static const String id = 'assignedTask';
#override
_assignedTaskState createState() => _assignedTaskState();
}
class _assignedTaskState extends State<assignedTask> {
String Title;
String Summary;
var tasks;
crudMedthods crudObj = new crudMedthods();
var documentID;
var documents;
Future<bool> addDialog(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Add Data', style: TextStyle(fontSize: 15.0)),
content: Container(
height: 125.0,
width: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'Enter Title'),
onChanged: (value) {
this.Title = value;
},
),
SizedBox(height: 5.0),
TextField(
decoration: InputDecoration(hintText: 'Enter Summary'),
onChanged: (value) {
this.Summary = value;
},
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Add'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
crudObj.addData({
'Title': this.Title,
'Summary': this.Summary
}).then((result) {
dialogTrigger(context);
}).catchError((e) {
print(e);
});
},
)
],
);
});
}
Future<bool> updateDialog(BuildContext context, selectedDoc) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Update Data', style: TextStyle(fontSize: 15.0)),
content: Container(
height: 125.0,
width: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'Title'),
onChanged: (value) {
this.Title = value;
},
),
SizedBox(height: 5.0),
TextField(
decoration: InputDecoration(hintText: 'Enter Summary'),
onChanged: (value) {
this.Summary = value;
},
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Update'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
crudObj.updateData(selectedDoc, {
'Title': this.Title,
'Summary': this.Summary
}).then((result) {
// dialogTrigger(context);
}).catchError((e) {
print(e);
});
},
)
],
);
});
}
Future<bool> dialogTrigger(BuildContext context) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Job Done', style: TextStyle(fontSize: 15.0)),
content: Text('Added'),
actions: <Widget>[
FlatButton(
child: Text('Alright'),
textColor: Colors.blue,
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
#override
void initState() {
crudObj.getData().then((results) {
setState(() {
tasks = results;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Assigned Tasks'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
addDialog(context);
},
),
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
crudObj.getData().then((results) {
setState(() {
tasks = results;
});
});
},
)
],
),
body: _TaskList(),
);
}
Widget _TaskList() {
if (tasks != null) {
return StreamBuilder(
stream: tasks,
// ignore: missing_return
builder: (context, snapshot) {
if (snapshot.data != null) {
return ListView.builder(
itemCount: snapshot.data.documents.length,
padding: EdgeInsets.all(7.0),
itemBuilder: (context, i) {
return ListTile(
title: Text(snapshot.data.documents[i].data["Title"]??""),
subtitle: Text(snapshot.data.documents[i].data["Summary"]??""),
/*onTap: () {
*//*
updateDialog(
context, snapshot.data.documents[i].documentID);
},*/
onTap: (){
Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailPage(snapshot.data.douments[i])));
}, onLongPress: () {
crudObj.deleteData(snapshot.data.documents[i].documentID);
},
);
},
);
}
return CircularProgressIndicator();
},
);
} else {
return Text('Loading, Please wait..');
}
}
}
When i press ontap it should go to the detail page which shows details of only that particular task(note: i now have only the values Title and summary for now, i will add rest later they should show in the detail page)
My detailview is as follows
class DetailPage extends StatelessWidget {
DocumentSnapshot detailDocument;
DetailPage(this.detailDocument);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text( detailDocument.data["Title"]),
),
body: Center(
child: Text(detailDocument.data["Summary"]),
),
);
}
}
I am getting an error
The following NoSuchMethodError was thrown building Builder(dirty):
Class 'QuerySnapshot' has no instance getter 'douments'.
Receiver: Instance of 'QuerySnapshot'
Tried calling: douments
The relevant error-causing widget was:
MaterialApp file:///C:/Users/TRICON/AndroidStudioProjects/taskmanager/lib/main.dart:21:14
When the exception was thrown, this was the stack:
0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
1 _assignedTaskState._TaskList.... (package:taskmanager/screens/assignedtask.dart:208:106)
You are using
Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailPage(snapshot.data.douments[i])));
instead of
Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailPage(snapshot.data.documents[i])));
It's just a difference in the spelling of douments as documents.