firestore_ui 1.20.0 copy "firestore_ui: ^1.20.0" to clipboard
firestore_ui: ^1.20.0 copied to clipboard

outdated

A port of firebase_database's FirebaseAnimatedList that works with cloud_firestore, with additional variants

example/lib/main.dart

// Copyright 2017, 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 'dart:async';

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

final String title = 'firestore_ui example';

typedef OnSnapshot = Function(DocumentSnapshot?);

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MaterialApp(
      title: title, home: MyHomePage(firestore: FirebaseFirestore.instance)));
}

class MessageListTile extends StatelessWidget {
  final int index;
  final DocumentSnapshot? document;
  final OnSnapshot? onTap;

  const MessageListTile({
    Key? key,
    required this.index,
    required this.document,
    required this.onTap,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    String message = 'No message retrieved!';
    if (document != null) {
      final data = document!.data();
      if (data != null) {
        final receivedMessage = data['message'];
        if (receivedMessage != null) message = receivedMessage;
      }
    }

    return ListTile(
      title: Text(message),
      subtitle: Text('Message ${this.index + 1}'),
      onTap: document != null && onTap != null
          ? () => onTap!.call(this.document!)
          : null,
    );
  }
}

class MessageGridTile extends StatelessWidget {
  final int index;
  final DocumentSnapshot? document;
  final OnSnapshot? onTap;

  const MessageGridTile({
    Key? key,
    required this.index,
    required this.document,
    required this.onTap,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: document != null && onTap != null
          ? () => onTap!.call(this.document!)
          : null,
      child: Container(
        color: Colors.green,
        child: Center(
          child: CircleAvatar(
            backgroundColor: Colors.white,
            child: Text('${this.index + 1}'),
          ),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final FirebaseFirestore firestore;

  MyHomePage({Key? key, required this.firestore}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final PageController _controller =
      PageController(initialPage: 0, keepPage: true);

  int _currentIndex = 0;

  CollectionReference get messages => widget.firestore.collection('messages');

  _addMessage() => messages.doc().set(<String, dynamic>{
        'message': 'Hello world!',
      });

  _removeMessage(DocumentSnapshot? snapshot) {
    if (snapshot != null)
      widget.firestore.runTransaction((transaction) async {
        transaction.delete(snapshot.reference);
      }).catchError((exception, stacktrace) {
        print("Couldn't remove item: $exception");
      });
  }

  void _updateIndex(int value) {
    if (mounted) {
      setState(() => _currentIndex = value);
      _controller.jumpToPage(_currentIndex);
    }
  }

  /// Feel free to experiment here with query parameters, upon calling `setState` or hot reloading
  /// the query will automatically update what's on the list. The easiest way to test this is to
  /// change the limit below, or remove it. The example collection has 500+ elements.
  Query get query => widget.firestore.collection('messages').limit(20);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: _updateIndex,
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.filter_1),
            label: "List",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.filter_2),
            label: "Grid",
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.filter_3),
            label: "Staggered",
          ),
        ],
      ),
      appBar: AppBar(
        title: Text(title),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _addMessage,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
      body: PageView(
        controller: _controller,
        children: <Widget>[
          FirestoreAnimatedList(
            debug: false,
            key: ValueKey("list"),
            query: query,
            onLoaded: (snapshot) =>
                print("Received on list: ${snapshot.docs.length}"),
            itemBuilder: (
              BuildContext context,
              DocumentSnapshot? snapshot,
              Animation<double> animation,
              int index,
            ) =>
                FadeTransition(
              opacity: animation,
              child: MessageListTile(
                index: index,
                document: snapshot,
                onTap: _removeMessage,
              ),
            ),
          ),
          FirestoreAnimatedGrid(
            key: ValueKey("grid"),
            query: query,
            onLoaded: (snapshot) =>
                print("Received on grid: ${snapshot.docs.length}"),
            crossAxisCount: 2,
            itemBuilder: (
              BuildContext context,
              DocumentSnapshot? snapshot,
              Animation<double> animation,
              int index,
            ) {
              return FadeTransition(
                opacity: animation,
                child: MessageGridTile(
                  index: index,
                  document: snapshot,
                  onTap: _removeMessage,
                ),
              );
            },
          ),
          FirestoreAnimatedStaggered(
            key: ValueKey("staggered"),
            onLoaded: (snapshot) =>
                print("Received on staggered: ${snapshot.docs.length}"),
            staggeredTileBuilder: (int index, DocumentSnapshot? snapshot) =>
                StaggeredTile.count(2, index.isEven ? 2 : 1),
            crossAxisCount: 4,
            query: query,
            itemBuilder: (
              BuildContext context,
              DocumentSnapshot? snapshot,
              Animation<double> animation,
              int index,
            ) {
              return FadeTransition(
                opacity: animation,
                child: MessageGridTile(
                  index: index,
                  document: snapshot,
                  onTap: _removeMessage,
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}