I am developing an app that allows users to check kit within bags on vehicles at their base station.
I so far have the app working so that it takes the user information at log in, and shows the bags available at their particular station, in this case 'Test Station'. I can successfully show a listView with the relevant bag information from Firestore 'bags' collection.
What I would like to do, is when a user taps on a listTile, to update the Boolean value for that particular bag (essentially for that particular document within the bags collection) from false to true and back again. I then want the UI to show a green or red circle Icon accordingly.
I can only work out how to do this when I hardcode the docID for the doc I want to update the boolean of, rather than doing it dynamically dependant on which listTile the user taps on. All help to resolve this appreciated!!
so if I call this function when in the onTap:
CollectionReference bags = FirebaseFirestore.instance.collection('bags');
Future<void> updateBagStatus() {
return bags
.doc('test_bag')
.update({'isChecked': true})
.then((value) => print("isChecked Updated"))
.catchError((error) => print('Failed: $error'));
}
then I can flip the Boolean from false to true for that hardcoded bag.
and this is the rest of the code that shows how I construct the listView builder.
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String thisUserFirstName = '';
String thisUserLastName = '';
String thisUserBase = '';
String thisStation = '';
String thisBagChecked = '';
CollectionReference usersCollection =
FirebaseFirestore.instance.collection('users');
CollectionReference bags = FirebaseFirestore.instance.collection('bags');
Future<void> updateBagStatus() {
return bags
.doc('test_bag')
.update({'isChecked': true})
.then((value) => print("isChecked Updated"))
.catchError((error) => print('Failed: $error'));
}
void _getData() async {
User user = FirebaseAuth.instance.currentUser!;
DocumentSnapshot thisUserSnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.get();
{
setState(
() {
thisUserFirstName = thisUserSnapshot['first name'];
thisUserLastName = thisUserSnapshot['last name'];
thisUserBase = thisUserSnapshot['base station'];
},
);
}
}
// return StreamBuilder(
// stream: isCheckedSnapshot,
// builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
// if (!snapshot.hasData) {
// print('There is no data');
// }
@override
void initState() {
super.initState();
_getData();
}
// int selectedIndex = 0;
@override
Widget build(BuildContext context) {
Stream<QuerySnapshot> bags = FirebaseFirestore.instance
.collection("bags")
.where("station", isEqualTo: thisUserBase)
.snapshots();
return Scaffold(
backgroundColor: Colors.grey[300],
appBar: AppBar(
leading: Icon(Icons.settings),
title: Text(
'Welcome $thisUserFirstName',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
actions: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: GestureDetector(
onTap: () {
FirebaseAuth.instance.signOut();
},
child: Row(
children: const [
Text('Sign Out'),
SizedBox(
width: 5,
),
Icon(Icons.logout),
],
),
),
),
],
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: 40),
MyProfileRow(
rowBanner: 'Signed in as:',
rowIcon: Icons.person,
userName: '$thisUserFirstName $thisUserLastName',
),
SizedBox(height: 20),
MyProfileRow(
rowBanner: 'Base Station:',
rowIcon: Icons.house,
userName: thisUserBase,
),
SizedBox(height: 30),
Text("All bags at $thisUserBase"),
SizedBox(
height: 10,
),
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: bags,
builder: (
BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot,
) {
if (snapshot.hasError) {
return Text('Error!');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
final data = snapshot.requireData;
return ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: ListTile(
title: Text('${data.docs[index]['name']}'),
subtitle: Text('${data.docs[index]['isChecked']}'),
trailing: Icon(
Icons.circle,
color: Colors.red,
),
onTap: updateBagStatus
// onTap: () {
// if (data.docs[index]['isChecked'] == true) {
// print('isChecked = True');
// }
// if (data.docs[index]['isChecked'] == false) {
// print('isChecked = False');
// }
// },
),
),
);
},
);
},
),
)
],
),
);
}
}
Click to see how I have Firestone set up:
Image of My Firestore Database:
Your approach is correct. You just need to pass the relevant values as function parameters as shown below:
Future<void> updateBagStatus(String docId, bool status) {
return bags
.doc(docId)
.update({'isChecked': status})
.then((value) => print("isChecked Updated"))
.catchError((error) => print('Failed: $error'));
}
onTap: () => updateBagStatus(!data.docs[index]['isChecked'], data.docs[index].id)