Achieving Cloud Firestore and Ml-Kit in Flutter Firebase

This is the fourth blog post of our Firebase series, presenting another two new features of this database i.e. Cloud Firestore, followed by Ml-Kit (Machine Learning Kit). Furthermore, Cloud Firestore is a NoSQL document-based database, whereas Ml-Kit is a powerful tool featuring machine learning expertise for Android and iOS devices. Well, let’s not take further time and try our best to implement Achieving Cloud Firestore and Ml-Kit in Flutter Firebase.


Note: If you haven’t gone through any of the previous posts, you can redirect from here.

Table of Contents

Project Overview

As before, we’re going to cope with the same Student Grading Application.

We shall be making three new files for add_student_grading, view_student_grading with Firestore, vis-à-vis ml_kit_integration for Ml Kit respectively.

Let’s now move to the next section and get to know Firestore.

Cloud Firestore

Cloud Firestore is a document-based NoSQL database from Firebase itself, designed for complex data synchronization for mobile and web applications in real-time. Moreover, there are various other unaddressed features:

NoSQL Database:

As per the above statement, Cloud Firestore uses a semi-structured document approach, efficient for fast and seamless data retrieval, instead of the traditional relational approach.

Real-time Synchronization:

Firestore is enabled with real-time data synchronization. When data gets updated in the DB itself, it immediately gets reflected in the UI as well, providing a more robust end-user experience.

Scalability:

With automatic scaling, Cloud Firestore accommodates changes in data volume vis-à-vis user traffic. Additionally, it supports both small and large-level applications.

Offline Capabilities:

Firestore also supports offline data access. With the device being unresponsive to the internet, it can still read and write any data. After a successful restoration of the internet, the data gets synced accordingly.

Document-Centric model:

As we mentioned, Cloud Firestore has a document-based structure. The data is organized into collections and each document within a collection is a JSON object. This simplifies the data retrieval process.

Querying and Indexing:

Cloud Firestore provides pre-built efficient queries and automatic indexing of data fields, allowing for efficient data storage and retrieval.

Cloud Firestore is among the list of popular services provided by Firebase itself. With the ability to handle complex data storage and retrieval, it has its own identity and is widely used by many developers worldwide.

Implementation:

Firstly, on the Firebase Portal – Build Section pane – Firestore Database.

Cloud Firestore

Create it and start in test mode for the initial.

Next, make some changes to the rules tab.

Default Rules:
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
Modified Rules:
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

Now, inside the Flutter project, add a new file namely add_student_grading_collection.dart, and copy the same snippet we had for real-time excluding the DB functions/methods.

Inside pubspec.yaml, add the relevant plugin:

cloud_firestore

Furthermore, add an instance of FirebaseFirestore:

final FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;

Note: As we discussed the flow of Cloud Firestore, we shall have the following structure to save the entire collection.

Collection Structure:

grade (collection title) -> current_user_id (doc) -> JSON(student_records)

Moreover, create a method in the same class and add the following code:

  uploadMarks(User currentUser) async {
    isLoading = true;

    Map<String, dynamic> body = {
      'id': Random().nextInt(100000).toString(),
      'name': _studentC.text,
      'phy': _phyC.text,
      'chem': _chemC.text,
      'math': _mathC.text,
      'url': imageUrl,
    };

    await _firebaseFirestore.collection(SgConstants.reference).doc(currentUser.uid)
    .set({"data": FieldValue.arrayUnion([body])},SetOptions(merge: true))
    .onError((error,  
    stackTrace) {
      setState(() {
        isLoading = false;
      });
      SgUtils().showSnackBar(error.toString());
    });

    setState(() {
      isLoading = false;

      _studentC.clear();
      _phyC.clear();
      _chemC.clear();
      _mathC.clear();
    });
    SgUtils().showSnackBar('Uploaded successfully');
  }

In the above-highlighted statement, the data is added as an array, followed by SetOptions → true, which merges the data with the existing and avoids overwriting the entire document.

Let’s now run the app and insert the record.

So, I have added two records.

Preview
Data being inserted into Cloud Firestore

We’re done with this part. Let’s now do something for this data retrieval.

Create a new file as student_grading_view_collection.dart.

This class would act the same as the Realtime Database, but just with a different variation, i.e. Cloud Firestore.

Create these instances and add the following snippet:

final FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
final auth = FirebaseAuth.instance.currentUser;

Now, there are two ways we can retrieve data.

FutureBuilder():

With the use of FutureBuilder, the snapshot will retrieve the data only once without any real-time updates.

Code Snippet:

FutureBuilder<DocumentSnapshot>(
          future: firebaseFirestore.collection(SgConstants.reference).doc(auth!.uid).get(),
          builder: (context, userSnapshot) {

            if(userSnapshot.hasData) {

              List<GradingModel> userList = [];
              Map<String, dynamic> item = userSnapshot.data!.data() as Map<String, dynamic>;

              item['data'].map((e) {
                var res = GradingModel.fromJson(e);
                userList.add(res);
              }).toList();

              return ListView.builder(
                itemCount: userList.length,
                shrinkWrap: true,
                itemBuilder: (context, i) {
                  return GradingCustomWidget(model: userList[i]);
                },
              );
            }

            else if(userSnapshot.data == null) {
              return const Center(
                child: CircularProgressIndicator(),
              );
            }

            else if(userSnapshot.hasError) {
              return Text(userSnapshot.error.toString());
            }

            return const SizedBox.shrink();
          },
        ),

StreamBuilder():

Document snapshots with real-time updates.

Code Snippet:

StreamBuilder<DocumentSnapshot>(
      stream:firebaseFirestore.collection(SgConstants.reference).doc(auth!.uid).snapshots(),
        builder: (context, userSnapshot) {

          if(userSnapshot.hasData) {

            List<GradingModel> userList = [];
            Map<String, dynamic> item = userSnapshot.data!.data() as Map<String, dynamic>;

            item['data'].map((e) {
              var res = GradingModel.fromJson(e);
              userList.add(res);
            }).toList();

            return ListView.builder(
              itemCount: userList.length,
              shrinkWrap: true,
              itemBuilder: (context, i) {
                return GradingCustomWidget(model: userList[i]);
              },
            );
          }

          else if(userSnapshot.data == null) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }

          else if(userSnapshot.hasError) {
            return Text(userSnapshot.error.toString());
          }

          return const SizedBox.shrink();
        },
      ),

Both of the above snippets fetch the collection via doc, (which represents the current UID).

We’re done with this section.

Let’s now shed some light on Ml-Kit with Firebase.

Machine Learning Kit

Machine Learning, a powerful SDK added to Firebase to bring Google’s expertise for Android and iOS apps, with the relevant plugins. Additionally, it is quite easy to implement, with just a few lines of code required.

Moreover, there is no need to have a deep understanding of AI or Neural Networks for this feature.

So, inside the Firebase Dashboard – Build – Machine Learning section.

Here’s a list of the following features that Ml-Kit offers:

Ml-Kit features

We shall look into Text Recognition and Image Labelling for now.

Head over to pub.dev and install the required package:

google_ml_kit

Text Recognition

Add a new file as ml_kit_text_rec_view.dart, and paste the following code snippet:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:google_ml_kit/google_ml_kit.dart';
import 'package:image_picker_plus/image_picker_plus.dart';

class MlKitTextRecView extends StatefulWidget {
  const MlKitTextRecView({super.key});

  @override
  State<MlKitTextRecView> createState() => _MlKitTextRecViewState();
}

class _MlKitTextRecViewState extends State<MlKitTextRecView> {

  File? inputImage;
  String detectedText = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Ml-Kit"),
      ),
      body: ListView(
        padding: EdgeInsets.all(10),
        children: [

          SizedBox(
            height: 40,
          ),
          InkWell(
            onTap: () => attachImage(context),
            child: Container(
              height: 170,
              width: double.infinity,
              decoration: BoxDecoration(
                color: Theme.of(context).primaryColor,
              ),
              child: inputImage == null ? Align(
                alignment: Alignment.center,
                child: Icon(Icons.image, color: Colors.white, size: 100,),
              ) : Image.file(inputImage!, fit: BoxFit.cover,),
            ),
          ),

          SizedBox(
            height: 20,
          ),
          Text(detectedText, textAlign: TextAlign.center,),
        ],
      ),
    );
  }

  Future<void> attachImage(BuildContext context) async {
    SelectedImagesDetails? image = await ImagePickerPlus(context).pickImage(source: 
    ImageSource.gallery);

    if(image != null) {
      inputImage = image.selectedFiles.first.selectedFile;
      setState(() {});
      recognizeText(inputImage!);
    }
  }

  Future<void> recognizeText(File image) async {
    final inputImage = InputImage.fromFile(image);
    final textRecognizer = GoogleMlKit.vision.textRecognizer();
    RecognizedText recognizedText = await textRecognizer.processImage(inputImage);
    await textRecognizer.close();

    detectedText = '';
    for(TextBlock textBlock in recognizedText.blocks) {
      for(TextLine line in textBlock.lines) {
        detectedText = detectedText + line.text;
      }
    }
    setState(() {});
  }
}
Preview
Text Recognition

Let’s now implement image labeling as well.

Create a new file as ml_kit_image_label.dart and add this snippet:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:google_ml_kit/google_ml_kit.dart';
import 'package:image_picker_plus/image_picker_plus.dart';

class MlKitImageLabelView extends StatefulWidget {
  const MlKitImageLabelView({super.key});

  @override
  State<MlKitImageLabelView> createState() => _MlKitImageLabelViewState();
}

class _MlKitImageLabelViewState extends State<MlKitImageLabelView> {
  File? inputImage;
  String capturedText = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Image Labelling"),
      ),
      body: ListView(
        padding: const EdgeInsets.all(10),
        children: [
          const SizedBox(
            height: 40,
          ),
          InkWell(
            onTap: () => attachImage(context),
            child: Container(
              height: 170,
              width: double.infinity,
              decoration: BoxDecoration(
                color: Theme.of(context).primaryColor,
              ),
              child: inputImage == null
                  ? const Align(
                      alignment: Alignment.center,
                      child: Icon(
                        Icons.image,
                        color: Colors.white,
                        size: 100,
                      ),
                    )
                  : Image.file(
                      inputImage!,
                      fit: BoxFit.cover,
                    ),
            ),
          ),
          const SizedBox(
            height: 20,
          ),
          Text(
            capturedText,
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  Future<void> attachImage(BuildContext context) async {
    SelectedImagesDetails? image =
        await ImagePickerPlus(context).pickImage(source: ImageSource.gallery);

    if (image != null) {
      inputImage = image.selectedFiles.first.selectedFile;
      setState(() {});
      imageLabelling(inputImage!);
    }
  }

  Future<void> imageLabelling(File image) async {
    final inputImage = InputImage.fromFile(image);

    final ImageLabelerOptions options = ImageLabelerOptions(confidenceThreshold: 0.5);
    final imageLabeler = ImageLabeler(options: options);

    await imageLabeler.close();
    final List<ImageLabel> labels = await imageLabeler.processImage(inputImage);

    capturedText = "";

    for (ImageLabel label in labels) {
      final String text = label.label;
      final int index = label.index;
      final double confidence = label.confidence;

      capturedText = ""
          "label: $text\n"
          "index: $index\n"
          "confidence: $confidence"
          "";
    }
    setState(() {});
  }
}
Preview
Image Labelling
Video Preview

So, this is it. We have reached the end of this blog post.

Hope you enjoyed reading this one.


Summing it up

In wrapping up, in Achieving Cloud Firestore and Ml-Kit in Flutter Firebase, we discussed other two brilliant features of this database, followed by its well-explained optimization approaches. Moreover, as in the previous ones, this blog post was filled with useful snippets, snapshots, and video previews.

However, if you find any information incomplete or not up to the mark, please jot it down in the comments below. I would love to hear from you.

Link to the Code Repository

Check out my YouTube channel for Flutter and GitHub tutorials

Thanks much for your precious time!

Flutter Directory – Firebase Series

Leave a Comment