cloud_firestore 0.14.1+3

Flutter Android iOS web

Flutter plugin for Cloud Firestore, a cloud-hosted, noSQL database with live synchronization and offline support on Android and iOS.

example/lib/main.dart

// Copyright 2020, the Chromium project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

/// Requires that a Firestore emulator is running locally.
/// See https://firebase.flutter.dev/docs/firestore/usage#emulator-usage
bool USE_FIRESTORE_EMULATOR = false;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  if (USE_FIRESTORE_EMULATOR) {
    FirebaseFirestore.instance.settings = Settings(
        host: 'localhost:8080', sslEnabled: false, persistenceEnabled: false);
  }
  runApp(FirestoreExampleApp());
}

/// The entry point of the application.
///
/// Returns a [MaterialApp].
class FirestoreExampleApp extends StatelessWidget {
  /// Given a [Widget], wrap and return a [MaterialApp].
  MaterialApp withMaterialApp(Widget body) {
    return MaterialApp(
      title: 'Firestore Example App',
      theme: ThemeData.dark(),
      home: Scaffold(
        body: body,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return withMaterialApp(Center(child: FilmList()));
  }
}

/// Holds all example app films
class FilmList extends StatefulWidget {
  @override
  _FilmListState createState() => _FilmListState();
}

class _FilmListState extends State<FilmList> {
  String _filterOrSort = "sort_year";

  _FilmListState();

  @override
  Widget build(BuildContext context) {
    Query query =
        FirebaseFirestore.instance.collection('firestore-example-app');

    void _onActionSelected(String value) async {
      if (value == "batch_reset_likes") {
        WriteBatch batch = FirebaseFirestore.instance.batch();

        await query.get().then((querySnapshot) async {
          querySnapshot.docs.forEach((document) {
            batch.update(document.reference, {'likes': 0});
          });

          await batch.commit();

          setState(() {
            _filterOrSort = "sort_year";
          });
        });
      } else {
        setState(() {
          _filterOrSort = value;
        });
      }
    }

    switch (_filterOrSort) {
      case "sort_year":

        /// Order by the production year. Set [descending] to [false] to reverse the order
        query = query.orderBy('year', descending: true);
        break;
      case "sort_likes_desc":

        /// Order by the number of likes. Set [descending] to [false] to reverse the order
        query = query.orderBy('likes', descending: true);
        break;
      case "sort_likes_asc":

        /// Order by the number of likes. Set [descending] to [false] to reverse the order
        query = query.orderBy('likes', descending: false);
        break;
      case "sort_score":

        /// Order by the score, and return only those which has one great than 90
        query = query.orderBy('score').where('score', isGreaterThan: 90);
        break;
      case "filter_genre_scifi":

        /// Return the movies which have the following categories
        query = query.where('genre', arrayContainsAny: ['Sci-Fi']);
        break;
      case "filter_genre_fantasy":

        /// Return the movies which have the following categories
        query = query.where('genre', arrayContainsAny: ['Fantasy']);
        break;
    }

    return Scaffold(
        appBar: AppBar(
          title: Text('Firestore Example: Movies'),
          actions: <Widget>[
            PopupMenuButton(
              onSelected: (String value) async {
                await _onActionSelected(value);
              },
              itemBuilder: (BuildContext context) {
                return [
                  PopupMenuItem(
                    value: "sort_year",
                    child: Text("Sort by Year"),
                  ),
                  PopupMenuItem(
                    value: "sort_score",
                    child: Text("Sort by Score"),
                  ),
                  PopupMenuItem(
                    value: "sort_likes_asc",
                    child: Text("Sort by Likes ascending"),
                  ),
                  PopupMenuItem(
                    value: "sort_likes_desc",
                    child: Text("Sort by Likes descending"),
                  ),
                  PopupMenuItem(
                    value: "filter_genre_fantasy",
                    child: Text("Filter genre Fantasy"),
                  ),
                  PopupMenuItem(
                    value: "filter_genre_scifi",
                    child: Text("Filter genre Sci-Fi"),
                  ),
                  PopupMenuItem(
                    value: "batch_reset_likes",
                    child: Text("Reset like counts (WriteBatch)"),
                  ),
                ];
              },
            ),
          ],
        ),
        body: StreamBuilder<QuerySnapshot>(
          stream: query.snapshots(),
          builder: (context, stream) {
            if (stream.connectionState == ConnectionState.waiting) {
              return Center(child: CircularProgressIndicator());
            }

            if (stream.hasError) {
              return Center(child: Text(stream.error.toString()));
            }

            QuerySnapshot querySnapshot = stream.data;

            return ListView.builder(
              itemCount: querySnapshot.size,
              itemBuilder: (context, index) => Movie(querySnapshot.docs[index]),
            );
          },
        ));
  }
}

/// A single movie row.
class Movie extends StatelessWidget {
  /// Contains all snapshot data for a given movie.
  final DocumentSnapshot snapshot;

  /// Initialize a [Move] instance with a given [DocumentSnapshot].
  Movie(this.snapshot);

  /// Returns the [DocumentSnapshot] data as a a [Map].
  Map<String, dynamic> get movie {
    return snapshot.data();
  }

  /// Returns the movie poster.
  Widget get poster {
    return Container(
      width: 100,
      child: Center(child: Image.network(movie['poster'])),
    );
  }

  /// Returns movie details.
  Widget get details {
    return Padding(
        padding: EdgeInsets.only(left: 8, right: 8),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            title,
            metadata,
            genres,
            Likes(
              reference: snapshot.reference,
              currentLikes: movie['likes'],
            )
          ],
        ));
  }

  /// Return the movie title.
  Widget get title {
    return Text("${movie['title']} (${movie['year']})",
        style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold));
  }

  /// Returns metadata about the movie.
  Widget get metadata {
    return Padding(
        padding: EdgeInsets.only(top: 8),
        child: Row(children: [
          Padding(
              child: Text('Rated: ${movie['rated']}'),
              padding: EdgeInsets.only(right: 8)),
          Text('Runtime: ${movie['runtime']}'),
        ]));
  }

  /// Returns a list of genre movie tags.
  List<Widget> genreItems() {
    List<Widget> items = <Widget>[];
    movie['genre'].forEach((genre) {
      items.add(Padding(
        child: Chip(
            label: Text(genre, style: TextStyle(color: Colors.white)),
            backgroundColor: Colors.lightBlue),
        padding: EdgeInsets.only(right: 2),
      ));
    });
    return items;
  }

  /// Returns all genres.
  Widget get genres {
    return Padding(
        padding: EdgeInsets.only(top: 8), child: Wrap(children: genreItems()));
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
        padding: EdgeInsets.only(bottom: 4, top: 4),
        child: Container(
          child: Row(
            children: [poster, Flexible(child: details)],
          ),
        ));
  }
}

/// Displays and manages the movie "like" count.
class Likes extends StatefulWidget {
  /// The [DocumentReference] relating to the counter.
  final DocumentReference reference;

  /// The number of current likes (before manipulation).
  final num currentLikes;

  /// Constructs a new [Likes] instance with a given [DocumentReference] and
  /// current like count.
  Likes({Key key, this.reference, this.currentLikes}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _Likes();
  }
}

class _Likes extends State<Likes> {
  int _likes;

  _onLike(int current) async {
    // Increment the "like" count straight away to show feedback to the user.
    setState(() {
      _likes = current + 1;
    });

    try {
      // Return and set the updated "likes" count from the transaction
      int newLikes = await FirebaseFirestore.instance
          .runTransaction<int>((transaction) async {
        DocumentSnapshot txSnapshot = await transaction.get(widget.reference);

        if (!txSnapshot.exists) {
          throw Exception("Document does not exist!");
        }

        int updatedLikes = (txSnapshot.data()['likes'] ?? 0) + 1;
        transaction.update(widget.reference, {'likes': updatedLikes});
        return updatedLikes;
      });

      // Update with the real count once the transaction has completed.
      setState(() {
        _likes = newLikes;
      });
    } catch (e) {
      print("Failed to update likes for document! $e");

      // If the transaction fails, revert back to the old count
      setState(() {
        _likes = current;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    int currentLikes = _likes ?? widget.currentLikes ?? 0;

    return Row(children: [
      IconButton(
          icon: Icon(Icons.favorite),
          iconSize: 20,
          onPressed: () {
            _onLike(currentLikes);
          }),
      Text("$currentLikes likes"),
    ]);
  }
}
822
likes
110
pub points
99%
popularity

Publisher

firebase.google.com

Flutter plugin for Cloud Firestore, a cloud-hosted, noSQL database with live synchronization and offline support on Android and iOS.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD (LICENSE)

Dependencies

cloud_firestore_platform_interface, cloud_firestore_web, firebase_core, firebase_core_platform_interface, flutter, meta, quiver

More

Packages that depend on cloud_firestore