CodeBlanks Logo Icon CodeBlanks

Challenge 3

Build a realtime chat screen with Firestore.

Challenge 3 - Firestore chat

In this challenge you will listen to messages from a Firestore collection with snapshots() and display them with a StreamBuilder. Each time a message is added, the stream emits new data.

StreamBuilder<QuerySnapshot>(
  stream: FirebaseFirestore.instance
      .collection('messages')
      .snapshots(),
  builder: (context, snapshot) {
    if (!snapshot.hasData) return Text('loading');
    return Text('${snapshot.data!.docs.length} messages');
  },
)

Practice First data with StreamController

In main, create a StreamController holding List<String> (streamCtrl). Add a three-element list to it. Await the first data with streamCtrl.stream.first and print its length. Then call streamCtrl.close().

Starter code

main.dart
import 'dart:async';

void main() async {
  // List<String> tutan bir StreamController oluştur (streamCtrl)
  // içine üç elemanlı bir liste ekle
  // stream'in ilk verisini bekle ve length'ini yazdır
}

Sample solution

main.dart
import 'dart:async';

void main() async {
  final streamCtrl = StreamController<List<String>>();
  streamCtrl.add(['a', 'b', 'c']);
  final data = await streamCtrl.stream.first;
  print(data.length);
  streamCtrl.close();
}

Expected output

3

Practice Create a StreamBuilder widget

In main, create a StreamController holding List<String> (streamCtrl). Create a StreamBuilder<List<String>> widget: set stream to streamCtrl.stream; the builder returns Text(snapshot.data!.length.toString()) if snapshot.hasData, else Text('yok'). Print the widget's runtimeType and call streamCtrl.close().

Starter code

main.dart
import 'dart:async';
import 'package:flutter/material.dart';

void main() {
  // List<String> tutan bir StreamController oluştur (streamCtrl)
  // StreamBuilder oluştur: stream olarak streamCtrl.stream ver
  // builder snapshot hasData ise data length string, değilse 'yok'
  // widget'ın runtimeType'ını yazdır
}

Sample solution

main.dart
import 'dart:async';
import 'package:flutter/material.dart';

void main() {
  final streamCtrl = StreamController<List<String>>();
  final widget = StreamBuilder<List<String>>(
    stream: streamCtrl.stream,
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return Text(snapshot.data!.length.toString());
      }
      return const Text('yok');
    },
  );
  print(widget.runtimeType);
  streamCtrl.close();
}

Expected output

StreamBuilder<List<String>>

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What type of object does snapshots() return?

  • Stream<QuerySnapshot> Correct answer
  • Future<QuerySnapshot>
  • QuerySnapshot
  • List<DocumentSnapshot>

Explanation: snapshots() returns a Stream<QuerySnapshot>; a new snapshot is emitted on every data change.

2 Give stream to StreamBuilder

Question
StreamBuilder<QuerySnapshot>(
  stream: FirebaseFirestore.instance
      .collection('messages')
      .____(),
  builder: (context, snapshot) { ... },
)
Answer
StreamBuilder<QuerySnapshot>(
  stream: FirebaseFirestore.instance
      .collection('messages')
      .snapshots(),
  builder: (context, snapshot) { ... },
)

Explanation: Calling snapshots() on a collection returns a real-time Stream<QuerySnapshot>; get returns a one-shot Future.

3 Firestore chat matches

Term Meaning
Firestore Database
snapshots Real-time stream
StreamBuilder Binds stream to widget
QuerySnapshot Query result

All lessons in Advanced