How to fix this,
error says,
════════ Exception caught by widgets library ═══════════════════════════════════
The following StateError was thrown building:
Bad state: field does not exist within the DocumentSnapshotPlatform
Another problem is when the user searches for something, the app should show the username without considering capital, simple words
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:insta/utils/colors.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({super.key});
#override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
final TextEditingController searchCon = TextEditingController();
bool isShowUsers = false;
#override
void dispose() {
searchCon.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: mobileBackgroundColor,
title: TextFormField(
controller: searchCon,
decoration: const InputDecoration(
labelText: "Search for a user",
),
onChanged: (value) {
setState(() {
isShowUsers = true;
});
},
// onFieldSubmitted: (String _) {
// setState(() {
// isShowUsers = true;
// });
// },
),
),
body: isShowUsers
? FutureBuilder(
future: FirebaseFirestore.instance
.collection('users')
.where(
'username',
isGreaterThanOrEqualTo: searchCon.text,
)
.get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: (snapshot.data! as dynamic).docs.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(
(snapshot.data! as dynamic).docs[index]
['photoUrl']),
),
title: Text(
(snapshot.data! as dynamic).docs[index]['username']),
);
},
);
},
)
: FutureBuilder(
future: FirebaseFirestore.instance.collection('posts').get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: const CircularProgressIndicator());
}
return StaggeredGridView.countBuilder(
crossAxisCount: 3,
itemCount: (snapshot.data! as dynamic).docs.length,
itemBuilder: (context, index) => Image.network(
(snapshot.data! as dynamic).docs[index]['postUrl'],
fit: BoxFit.cover,
),
staggeredTileBuilder: (index) => StaggeredTile.count(
(index % 7 == 0) ? 2 : 1, (index % 7 == 0) ? 2 : 1),
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
);
},
),
);
}
}
`
Got this error while working with firebase its due to when you are trying to access the document doesn't exist or check the spelling, syntax when you access them
Related
I am not an expert in flutter, I am still learning it but I cannot understand where I am wrong.
I thank anyone who wants to help me
I am not an expert in flutter, I am still learning it but I cannot understand where I am wrong.
I thank anyone who wants to help me
I am not an expert in flutter, I am still learning it but I cannot understand where I am wrong.
I thank anyone who wants to help me
import 'package:flutter/material.dart';
import 'package:todo_app/database_helper.dart';
import 'package:todo_app/screens/taskpage.dart';
import 'package:todo_app/widgets.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DatabaseHelper _dbHelper = DatabaseHelper();
#override
Widget build(
BuildContext context,
) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.deepPurple,
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TaskPage(),
),
);
},
),
body: SafeArea(
child: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 24),
margin: EdgeInsets.only(bottom: 20),
color: Colors.grey[100],
child: Stack(children: [
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Container(
margin: EdgeInsets.only(bottom: 32),
child: Text(
'Logo',
style: TextStyle(fontSize: 22),
),
),
Expanded(
child: FutureBuilder(
future: _dbHelper.getTasks(),
builder: (context, AsyncSnapshot snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return TaskCardWidget(
title: snapshot.data[index].title,
desc: snapshot.data[index].description,
);
});
},
),
),
])
]),
),
),
);
}
}
// This is the database class instead
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:todo_app/models/task.dart';
class DatabaseHelper {
Future<Database> database() async {
return openDatabase(
join(await getDatabasesPath(), 'todo_database.db'),
onCreate: (db, version) {
return db.execute(
"CREATE TABLE task(id INTEGER PRIMARY KEY, title TEXT, description TEXT)",
);
},
version: 1,
);
}
Future<void> insertTask(Task task) async {
Database _db = await database();
await _db.insert('task', task.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace);
}
Future<List<Task>> getTasks() async {
final Database _db = await database();
final List<Map<String, dynamic>> taskMap = await _db.query('tasks');
return List.generate(
taskMap.length,
(index) => Task(
id: taskMap[index]['id'],
title: taskMap[index]['title'],
description: taskMap[index]['description'],
));
}
}
Initially when your Future isn't completed, you don't have the data from the AsyncSnapshot. Try adding the following checks in your FutureBuilder.
FutureBuilder(
future: _dbHelper.getTasks(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text('${snapshot.error}');
} else if (snapshot.hasData) {
return ListView.builder(...);
}
return Center(child: CircularProgressIndicator()); // Default loading
},
)
I am trying to change the background of a selected tile from a ListTile.
I searched and found the following two posts, however non of them worked with my problem.
Post1
Post2
The better I got was with the help from #CopsOnRoad's answere.
With the following code, if I select multiple tiles, all remain select. How to select only one at the time and deselect the previous selected?
The tile index is limited by itemCount: is books.length.
List<Favorited> books;
// todo: this needs to be changed, has a hard coded value of 200
List<bool> _selected = List.generate(200, (i) => false); // Pre filled list
#override
Widget build(BuildContext context) {
final booksProvider = Provider.of<Model>(context);
return Container(
child: StreamBuilder(
stream: booksProvider.getUserFavList('103610812025'),
builder: (context, AsyncSnapshot<List<Favorited>> snapshot) {
if (snapshot.hasData) {
books= snapshot.data.toList();
return ListView.builder(
itemCount: books.length,
itemBuilder: (buildContext, index) {
return Container(
color: _selected[index] ? Colors.amber : Colors.transparent,
child: ListTile(
title: InkWell(
child: Text(snapshot.data[index].title),
onTap:() {
setState(() {
_selected[index] = !_selected[index];
});
}),
subtitle: Text(snapshot.data[index].name),
),
);
});
} else {
return Text('Fetching');
}
}),
);
Let a one variable to save selected tile index.
List<Favorited> books;
// todo: this needs to be changed, has a hard coded value of 200
List<bool> _selected = List.generate(200, (i) => false); // Pre filled list
int selectedIndex;
#override
Widget build(BuildContext context) {
final booksProvider = Provider.of<Model>(context);
return Container(
child: StreamBuilder(
stream: booksProvider.getUserFavList('103610812025'),
builder: (context, AsyncSnapshot<List<Favorited>> snapshot) {
if (snapshot.hasData) {
books= snapshot.data.toList();
return ListView.builder(
itemCount: books.length,
itemBuilder: (buildContext, index) {
return Container(
color: selectedIndex == index ? Colors.amber : Colors.transparent,
child: ListTile(
title: InkWell(
child: Text(snapshot.data[index].title),
onTap:() {
setState(() {
selectedIndex = index;
});
}),
subtitle: Text(snapshot.data[index].name),
),
);
});
} else {
return Text('Fetching');
}
}),
);
I build a quiz app and i use firestore for the data, i need a code for this : when the user select answer 1 he goes to page A , but when he select answer 2 he goes to page B ... etc
This is where am i : all the answers go to the same page when i tap on it, i want for every answer has his own page
This is my code :
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class question14 extends StatefulWidget {
#override
_question14State createState() => _question14State();
}
class _question14State extends State<question14> {
int selectedIndex
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance.collection('numberzz').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading ...');
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.fromLTRB(100.0, 0.0, 0.0, 0.0),
itemExtent: 200.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
final DocumentSnapshot document =
snapshot.data.documents[index];
return Container(
padding: EdgeInsets.fromLTRB(0.0, 300.0, 0.0, 450.0),
child: ListTile(
contentPadding: selectedIndex == index
? EdgeInsets.all(0.0)
: EdgeInsets.all(25.0),
title: Image.network(
document['number'],
),
selected: selectedIndex == index,
onTap: () {
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'vote': freshSnap['vote'] + 1,
});
});
Navigator.push(
context, MaterialPageRoute(
builder: (context) => new page()));
setState(() {
selectedIndex = index;
});
},
),
);
},
);
}));
}
}
thanks for your help !
You can check which index is selected before navigating. Kind of conditional navigation.
switch(selectedIndex){
case 0:
Navigator.of(context).push(.....(Page A));
break;
case 1:
.......
break;
I think you get the point.
But this code should come after
setState(() { selectedIndex = index };
i'm creating a quiz app and i want to make some questions with single selection answer,
this is what it looks like for now :
Full code :
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class question14 extends StatefulWidget {
#override
_question14State createState() => _question14State();
}
class _question14State extends State<question14> {
final isSelected = [false, false, false];
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance
.collection('numberzz')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading ...');
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.fromLTRB(100.0, 0.0, 0.0, 0.0),
itemExtent: 200.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
final DocumentSnapshot document =
snapshot.data.documents[index];
return
Container(
padding: EdgeInsets.fromLTRB(0.0, 300.0, 0.0, 450.0),
child: ListTile(
contentPadding: isSelected[index]
? EdgeInsets.all(0.0)
: EdgeInsets.all(25.0),
title: Image.network(
document['number'],
),
selected: !isSelected[index],
onTap: () {
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'vote': freshSnap['vote'] + 1,
});
});
setState(() {
isSelected[index] = !isSelected[index];
});
},
),
);
},
);
);
}
}
thanks you so much for your help !
Instead of using list of booleans, you can just store the selected index.
I used selectedIndex to have the answer's selection which is selected by the user at last.
Updated code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class question14 extends StatefulWidget {
#override
_question14State createState() => _question14State();
}
class _question14State extends State<question14> {
int selectedIndex = 0;//for unselect, you can use null
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance.collection('numberzz').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading ...');
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.fromLTRB(100.0, 0.0, 0.0, 0.0),
itemExtent: 200.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
final DocumentSnapshot document =
snapshot.data.documents[index];
return Container(
padding: EdgeInsets.fromLTRB(0.0, 300.0, 0.0, 450.0),
child: ListTile(
contentPadding: selectedIndex == index
? EdgeInsets.all(0.0)
: EdgeInsets.all(25.0),
title: Image.network(
document['number'],
),
selected: selectedIndex == index,
onTap: () {
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'vote': freshSnap['vote'] + 1,
});
});
setState(() {
selectedIndex = index;
});
},
),
);
},
);
}));
}
}
I have a page which displays 2 elements, both of them are different StreamBuilder but the second one depends on the first one.
To make it more clear I display this:
Firebase documents (list)
Firebase user
If we sign out both StreamBuilder disappear. That's fine, but my problem comes when I need to select a document from the list:
return ListTile(
leading: FlutterLogo(size: 40.0),
title: Text(set["title"]),
selected: _selected[index],
trailing: Badge(
badgeColor: Colors.grey,
shape: BadgeShape.circle,
toAnimate: true,
onTap: () => setState(() => _selected[index] = !_selected[index]),
);
Everytime I do the SetState() I refresh the first StreamBuilder (not sure why) and with this the second one.
This is the list widget:
Widget _mySetsLists(BuildContext context) {
List<bool> _selected = List.generate(20, (i) => false);
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (context, snapshot) {
FirebaseUser user = snapshot.data;
if (snapshot.hasData) {
return StreamBuilder(
stream: Firestore.instance
.collection('users')
.document(user.uid)
.collection('sets')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot set = snapshot.data.documents[index];
return ListTile(
leading: FlutterLogo(size: 40.0),
title: Text(set["title"]),
selected: _selected[index],
onTap: () => setState(() => _selected[index] = !_selected[index]),
);
},
);
} else {
return Center(
child: new CircularProgressIndicator(),
);
}
},
);
} else {
return Text("loadin");
}
},
);
}
}
And this is the user profile:
class UserProfileState extends State<UserProfile> {
#override
Widget build(BuildContext context) {
return SliverList(
delegate: SliverChildListDelegate(
[
_mySetsLists(context),
Divider(),
StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
FirebaseUser user = snapshot.data;
if (user == null) {
return Text('not logged in');
}
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(
user.photoUrl,
),
),
title: Text(user.displayName),
subtitle: Text(user.email),
trailing: new IconButton(
icon: new Icon(Icons.exit_to_app),
highlightColor: Colors.pink,
onPressed: () {
authService.signOut();
}),
);
} else {
return Text("loading profile"); // <---- THIS IS WHAT I SEE
}
},
),
],
),
);
}
I also went through the same difficulty, but this is the trick i used
var itemsData = List<dynamic>();
var _documents = List<DocumentSnapshot>();
#override
void initState() {
// TODO: implement initState
super.initState();
getData();
}
getData(){
Firestore.instance
.collection('users')
.document(currentUser.uid)
.collection('set')
.getDocuments()
.then((value) {
value.documents.forEach((result) {
setState(() {
_documents.add(result);
itemsData.add(result.data);
});
});
});
}
replace your listview builder will be like this
ListView.builder(
shrinkWrap: true,
itemCount: _documents.length,
itemBuilder: (context, index) {
return ListTile(
title:Text(itemsData[index]['name'])
)
})
Hope it helps!!
If you pretend to use setstat a lot using the stream you can download the data locally. So every reload will not download data again, but just show the local data.
First step: declare the variable that will store data locally.
QuerySnapshot? querySnapshotGlobal;
Then where you read the streamData, first check if the local data you just declared is empty:
//check if its empty
if(querySnapshotGlobal==null)
//as its empty, we will download it from firestore
StreamBuilder<QuerySnapshot>(
stream: _queryAlunos.snapshots(),
builder: (context, stream){
if (stream.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
else if (stream.hasError) {
return Center(child: Text(stream.error.toString()));
}
else if(stream.connectionState == ConnectionState.active){
//QuerySnapshot? querySnapshot = stream.data;
//instead of save data here, lets save it in the variable we declared
querySnapshotGlobal = stream.data;
return querySnapshotGlobal!.size == 0
? Center(child: Text('Sem alunos nesta turma'),)
: Expanded(
child: ListView.builder(
itemCount: querySnapshotGlobal!.size,
itemBuilder: (context, index){
Map<String, dynamic> map = querySnapshotGlobal!.docs[index].data();
//let it build
return _listDeAlunoswid(map, querySnapshotGlobal!.docs[index].id);
},
),
);
}
return CircularProgressIndicator();
},
)
else
//now, if you call setstate, as the variable with the data is not empty, will call it from here e instead of download it again from firestore, will load the local data
Expanded(
child: ListView.builder(
itemCount: querySnapshotGlobal!.size,
itemBuilder: (context, index){
Map<String, dynamic> map = querySnapshotGlobal!.docs[index].data();
return _listDeAlunoswid(map, querySnapshotGlobal!.docs[index].id);
},
),
),
Hope it helps you save some money!