Recap
On Day 9 we access the device camera and stored the photo in cloud storage.
Overview
In this post, we will discuss retrieving real time data from cloud firestore and displaying it to the user.
Going Deeper
Retrieval and display of data from cloud firestore are divided into three (3) main parts. This division is done for readability and maintainability purposes.
getAllFarmers method
class FarmerService {
final farmerRef =
FirebaseFirestore.instance.collection('farmers').withConverter(
fromFirestore: (snapshot, _) =>
FarmerServiceModel.fromJson(snapshot.data()!),
toFirestore: (farmerModel, _) => farmerModel.toJson(),
);
Stream<QuerySnapshot<FarmerServiceModel>> getAllFarmers() {
return farmerRef.snapshots();
}
}
The getAllFarmers
method returns a Stream<QuerySnapshot<FarmerServiceModel>>
to AllFarmerCommand().run()
AllFarmerCommand().run()
class AllFarmerCommand extends BaseCommand {
AllFarmerCommand(BuildContext c) : super(c);
Stream<QuerySnapshot<FarmerServiceModel>> run() {
farmerModel.farmers = farmerService.getAllFarmers();
return farmerModel.farmers;
}
}
This method calls farmerService.getAllFarmers();
, assigns the returned stream to FarmerModel.farmers and to the method the _AllFarmerScreenController()
AllFarmerScreen
class AllFarmerScreen extends StatefulWidget {
static String routeName = 'AllFarmerScreen';
const AllFarmerScreen({
Key? key,
}) : super(key: key);
@override
_AllFarmerScreenController createState() => _AllFarmerScreenController();
}
This widget is the All Farmers Screen. It is comprised of a controller and layout widget. This widget is responsible for the screen logic and layout respectively.
AllFarmerScreenController
class _AllFarmerScreenController extends State<AllFarmerScreen> {
late Stream<QuerySnapshot<FarmerServiceModel>> stream;
@override
Widget build(BuildContext context) => _AllFarmerScreenView(this);
@override
void initState() {
super.initState();
stream = AllFarmerCommand(context).run();
// stream = Provider.of<FarmerModel>(context, listen: false).farmers;
}
}
Stream<QuerySnapshot<FarmerServiceModel>>
from farmerService.getAllFarmers();
is stored in a variable called stream when iniState()
is called by flutter.
AllFarmerScreenView
class _AllFarmerScreenView
extends WidgetView<AllFarmerScreen, _AllFarmerScreenController> {
final state;
const _AllFarmerScreenView(this.state) : super(state);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('All Farmers'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: Center(
child: Text(
'Farmer Register',
style: TextStyles.title.bold,
),
),
),
Expanded(
child: StreamBuilder<QuerySnapshot<FarmerServiceModel>>(
stream: state.stream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: SpinKitDoubleBounce(
color: Colours.accentColor(context),
));
} else if (snapshot.hasError) {
SnackBars.errorSnackBar(
content: 'Something went wrong', context: context);
print('something went wrong');
return Text('Something went wrong');
} else if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
} else
return ListView(
children: snapshot.data!.docs
.map((DocumentSnapshot<FarmerServiceModel> document) {
FarmerServiceModel farmer = document.data()!;
return FarmerIdentificationCard(
farmer: farmer,
);
}).toList(),
);
},
),
)
],
),
);
}
}
This widget is responsible for the layout of the AllFarmerScreen
. We will discuss the stream builder part of the code.
Expanded(
child: StreamBuilder<QuerySnapshot<FarmerServiceModel>>(
stream: state.stream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: SpinKitDoubleBounce(
color: Colours.accentColor(context),
));
} else if (snapshot.hasError) {
SnackBars.errorSnackBar(
content: 'Something went wrong', context: context);
print('something went wrong');
return Text('Something went wrong');
} else if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
} else
return ListView(
children: snapshot.data!.docs
.map((DocumentSnapshot<FarmerServiceModel> document) {
FarmerServiceModel farmer = document.data()!;
return FarmerIdentificationCard(
farmer: farmer,
);
}).toList(),
);
},
),
)
Stream builder will receive updates every time a document is added, deleted or edited in the farmers collection.
Before we extract any documents from the snapshot, we do three (3) main checks. First, we check for data in the snapshot, secondly, we check for errors and lastly we check for the connection state. Once we pass the checks, we return a listview.
Within the listview, each document from the snapshot is converted to a FarmerIdentificationCard()
widget. Screenshot of the Identification card is shown below.
Wrap Up
In this post, we discussed how to retrieve data from a cloud firestore collection as a Stream<QuerySnapshot
. We then used the snapshot to create a Farmer Identification Card widget for each document in the snapshot.
Connect with me
Thank you for reading my post. Feel free to subscribe below to join me on the #100DaysOfCodeChallenge or connect with me on LinkedIn and Twitter. You can also buy me a book to show your support.
Top comments (0)