DEV Community

Curtly Critchlow
Curtly Critchlow

Posted on • Updated on

#100DaysOfCodeChallenge - Crop Management Information System - Day 10

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();
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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(),
                  );
              },
            ),
          )
        ],
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

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(),
                  );
              },
            ),
          )
Enter fullscreen mode Exit fullscreen mode

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.

Preview of Farmer Profile picture in cloud storage

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.

Discussion (0)