what is missing here ? Flutter - single selection - flutter

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;
});
},
),
);
},
);
}));
}
}

Related

Bad state: field does not exist within the DocumentSnapshotPlatform | flutter

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

how can I put a if else statement for showing a loading screen in here flutter

how can I put an if-else statement for showing a loading screen in here flutter here is my code?
it's showing an error screen every time I reload my app but after a few seconds it displays all the data I want to put a loading indicator instead of showing that error screen
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:flutter_swiper/flutter_swiper.dart';
import 'dart:convert';
class Search extends StatefulWidget {
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
List users;
Future<bool> _getposts() async {
String serviceurl =
"http://spiro-learn.herokuapp.com/api/video-list/?format=json";
var response = await http.get(serviceurl);
setState(() {
users = jsonDecode(response.body.toString());
});
return true;
}
#override
void initState() {
super.initState();
this._getposts();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox(
child: Swiper(
itemWidth: 400,
itemHeight: 300,
layout: SwiperLayout.DEFAULT,
scrollDirection: Axis.horizontal,
viewportFraction: 0.4,
scale: 0.5,
itemCount: users.length == null ? 0 : users.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(users[index]["title"]),
subtitle: Text('${users[index]['likes']}'),
);
},
),
),
);
}
}
Scaffold(
body: users == null? CircularProgressIndicator(): SizedBox(
child: Swiper(
itemWidth: 400,
itemHeight: 300,
layout: SwiperLayout.DEFAULT,
scrollDirection: Axis.horizontal,
viewportFraction: 0.4,
scale: 0.5,
itemCount: users.length == null ? 0 : users.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(users[index]["title"]),
subtitle: Text('${users[index]['likes']}'),
);
},
),
),
);
check this out!
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:flutter_swiper/flutter_swiper.dart';
import 'dart:convert';
class Search extends StatefulWidget {
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
List users;
Future _future;
Future<bool> _getposts() async {
String serviceurl =
"http://spiro-learn.herokuapp.com/api/video-list/?format=json";
var response = await http.get(serviceurl);
setState(() {
users = jsonDecode(response.body.toString());
});
return true;
}
#override
void initState() {
super.initState();
_future = _getposts();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _future,
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.done){
if(snapshot.hasData){
return SizedBox(
child: Swiper(
itemWidth: 400,
itemHeight: 300,
layout: SwiperLayout.DEFAULT,
scrollDirection: Axis.horizontal,
viewportFraction: 0.4,
scale: 0.5,
itemCount: users.length == null ? 0 : users.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(users[index]["title"]),
subtitle: Text('${users[index]['likes']}'),
);
},
),
);
}
}else
return Center(child:
CircularProgressIndicator(),);
}
),
);
}
}

Flutter how to change the background color of a selected tile from a ListTile

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');
}
}),
);

Can't retrieve a number of document into firestore flutter

I have a small problem, I need to retrieve into my list a collection retrieved by StreamBuilder from Firestore.
I am using snapshot.data.documents.lenght but once I add it I got error:
Class 'DocumentSnapshot' has no instance getter 'documents'.
Receiver: Instance of 'DocumentSnapshot'
Tried calling: documents
this is my code:
Stream<DocumentSnapshot> getDatabase() async* {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
yield* Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
}
#override
Widget build(BuildContext context,) {
return StreamBuilder(
stream: getDatabase(),
builder: (context, snapshot,) {
if (snapshot.data != null) {
return Column(
children: <Widget>[
Container(
height: 500,
child: ListView.builder(
shrinkWrap: true,
itemCount: 2,
itemBuilder: (BuildContext context, int index) {
return Card(
color: Color(0xFF1f2032),
elevation: 15,
child: Text(
snapshot.data['phone']..
just change your code as following
Stream dataStream
then
#override
void initState() {
getDatabase().then((value) {
dataStream = value;
setState(() {});
});
super.initState();
}
the funcion getDatbase()
getDatabase() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
yield* Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
}
then
#override
Widget build(BuildContext context,) {
return StreamBuilder(
stream: dataStream,
builder: (context, snapshot,) {
if (snapshot.data != null) {
return Column(
children: <Widget>[
Container(
height: 500,
child: ListView.builder(
shrinkWrap: true,
itemCount: 2,
itemBuilder: (BuildContext context, int index) {
return Card(
color: Color(0xFF1f2032),
elevation: 15,
child: Text(
snapshot.data['phone']..
Try this,
StreamBuilder(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<DocumentSnapshot>> snapshots) {
if (snapshots.connectionState == ConnectionState.active &&
snapshots.hasData) {
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshots.data.length,
itemBuilder: (BuildContext context, int index) {
//do something with snapshot.
}
}
return Container();
},
),
);
} else {
return Container();
}
},
),
Initialise your stream like this,
Stream<DocumentSnapshot> stream;
Future<dynamic> getDatabase() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
setState(() {
stream=Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
});
}
You can call getDatabase() in initState.
Update:-
This is your full code.
class DataCo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.blue,
),
body: Column(
children: [
CollectData(),
],
),
);
}
}
class CollectData extends StatefulWidget {
#override
_CollectDataState createState() => _CollectDataState();
}
class _CollectDataState extends State<CollectData> {
final String phone;
final String wife;
final String location;
_CollectDataState({this.phone, this.wife, this.location});
#override
void initState() {
super.initState();
getDatabase();
}
Stream<DocumentSnapshot> stream;
Future<dynamic> getDatabase() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
setState(() {
stream=Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
});
}
#override
Widget build(BuildContext context,) {
return StreamBuilder(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshots) {
if (snapshots.connectionState == ConnectionState.active &&
snapshots.hasData) {
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshots.data.length,
itemBuilder: (BuildContext context, int index) {
//do something with snapshot.
}
}
return Container();
},
),
);
} else {
return Container();
}
},
);
}
}
class NoData extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: [
Text('No Data available'),
],
);
}
}

single document in same collection Firestore Flutter

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 };