firebase_core_plus 1.0.0 copy "firebase_core_plus: ^1.0.0" to clipboard
firebase_core_plus: ^1.0.0 copied to clipboard

A Flutter package for network operations.

Repository on GitHub | Report an Issue

firebase_core_plus Package #

A Flutter package that extends Firebase Core with strong typing and serialization capabilities for Firestore operations.

Features #

  • Strong Typing: Type-safe Firestore operations with generic classes
  • Automatic Serialization: Built-in JSON serialization/deserialization
  • CRUD Operations: Complete Create, Read, Update, Delete operations
  • Real-time Streams: Live data updates with typed streams
  • Search Capabilities: Advanced search with multiple field support
  • Sub-collections: Full support for Firestore sub-collections
  • Interface-based: Enforce consistent model structure across your app

Installation #

dependencies:
  firebase_core_plus: <latest_version>

Example #

Here is a complete example using all main features of the package:

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: const FirebaseOptions(
      apiKey: "YOUR_API_KEY",
      authDomain: "YOUR_PROJECT.firebaseapp.com",
      projectId: "YOUR_PROJECT",
      storageBucket: "YOUR_PROJECT.appspot.com",
      messagingSenderId: "YOUR_SENDER_ID",
      appId: "YOUR_APP_ID",
    ),
  );
  FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
  runApp(const MyApp());
}

// Model implementing InterfacePlus
class Cart implements InterfacePlus {
  Cart({required this.uid, required this.name, required this.price});

  @override
  String? uid;
  final String name;
  final double price;

  @override
  Map<String, dynamic> get json => {
    'uid': uid,
    'name': name,
    'price': price,
  };

  static Cart withMap(Map<String, dynamic> map) => Cart(
    uid: map['uid'],
    name: map['name'],
    price: (map['price'] as num).toDouble(),
  );

  double get priceWithTVA => price * 1.2;
  bool get isExpensive => price > 50;
}

// Sub-collection model
class CartItem implements InterfacePlus {
  CartItem({required this.uid, required this.label, required this.qty});

  @override
  String? uid;
  final String label;
  final int qty;

  @override
  Map<String, dynamic> get json => {
    'uid': uid,
    'label': label,
    'qty': qty,
  };

  static CartItem withMap(Map<String, dynamic> map) => CartItem(
    uid: map['uid'],
    label: map['label'],
    qty: map['qty'],
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FirestorePlus Demo',
      theme: ThemeData(primarySwatch: Colors.indigo),
      home: const CartDemoPage(),
    );
  }
}

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

  @override
  State<CartDemoPage> createState() => _CartDemoPageState();
}

class _CartDemoPageState extends State<CartDemoPage> {
  late final FirestorePlus<Cart> cartCollection;
  String? lastAddedId;
  List<CartItem> cartItems = [];

  @override
  void initState() {
    super.initState();
    cartCollection = FirestorePlus<Cart>.instance(
      tConstructor: Cart.withMap,
      path: 'carts',
    );
  }

  Future<void> _addCart() async {
    final cart = Cart(uid: '', name: 'Produit ${DateTime.now().millisecondsSinceEpoch}', price: 19.99);
    final id = await cartCollection.add(object: cart);
    setState(() => lastAddedId = id);
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Ajouté avec id: $id')));
  }

  Future<void> _addItemToCart() async {
    if (lastAddedId == null) return;
    
    final cartPlus = FirestorePlus<Cart>.instance(
      tConstructor: Cart.withMap,
      path: 'carts',
      uid: lastAddedId,
    );
    
    final itemsPlus = cartPlus.subCollection<CartItem>(
      subPath: 'items',
      itemUid: null,
      tConstructor: CartItem.withMap,
    );
    
    final item = CartItem(uid: '', label: 'Item ${DateTime.now().millisecondsSinceEpoch}', qty: 1);
    await itemsPlus.add(object: item);
    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Item ajouté au panier.')));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('FirestorePlus Demo')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Row(
              children: [
                Expanded(
                  child: ElevatedButton(
                    onPressed: _addCart,
                    child: const Text('Add Cart'),
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: ElevatedButton(
                    onPressed: _addItemToCart,
                    child: const Text('Add Item'),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 24),
            const Text('Real-time Carts Stream:', style: TextStyle(fontWeight: FontWeight.bold)),
            Expanded(
              child: StreamBuilder<List<Cart>>(
                stream: cartCollection.streams,
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return const Center(child: CircularProgressIndicator());
                  }
                  final carts = snapshot.data ?? [];
                  if (carts.isEmpty) {
                    return const Center(child: Text('No carts available.'));
                  }
                  return ListView.builder(
                    itemCount: carts.length,
                    itemBuilder: (context, index) {
                      final cart = carts[index];
                      return ListTile(
                        title: Text(cart.name),
                        subtitle: Text('Price: ${cart.price} € | TTC: ${cart.priceWithTVA.toStringAsFixed(2)} €'),
                        trailing: cart.isExpensive
                            ? const Icon(Icons.warning, color: Colors.orange)
                            : const Icon(Icons.check_circle, color: Colors.green),
                      );
                    },
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Parameters #

FirestorePlus #

Parameter Type Required Description
tConstructor T Function(Map<String, dynamic>) Yes Constructor function for type-safe object creation
path String Yes Firestore collection path
uid String? No Document ID (default: "none")
app String? No Firebase app name
limit int No Query limit (default: 10)
subPath String? No Sub-collection path

CRUD Operations #

Method Return Type Description
add(object) Future<String> Add document and return ID
update(object) Future<String> Update existing document
delete Future<String> Delete document
addByUid(object) Future<void> Add document with specific UID

Stream Operations #

Property Return Type Description
stream Stream<T> Stream of single document
streams Stream<List<T>> Stream of collection
streamSubCollection Stream<Map<String, Stream<List<T>>>> Stream of sub-collections

Future Operations #

Property Return Type Description
future Future<T> Single document
futures Future<List<T>> Collection
futureSubCollection Future<Map<String, Stream<List<T>>>> Sub-collections

Search Operations #

Method Parameters Description
futureWithSearch searchField, search Search by single field
futureWithSearch2 searchField1, search1, searchField2, search2 Search by two fields
streamWithSearch searchField, search Stream search by single field
streamWithSearch2 searchField1, search1, searchField2, search2 Stream search by two fields

Sub-collection Operations #

Method Parameters Description
subCollection<U> subPath, itemUid, tConstructor Create sub-collection instance

InterfacePlus #

All models must implement this interface:

Property/Method Type Description
uid String? Document ID
json Map<String, dynamic> JSON serialization
withMap(map) InterfacePlus JSON deserialization

Best Practices #

  1. Always implement InterfacePlus in your models for consistency
  2. Use meaningful model names and properties
  3. Handle errors appropriately in your streams and futures
  4. Use sub-collections for related data (e.g., user posts, order items)
  5. Leverage streams for real-time updates in your UI
  6. Use type-safe constructors for reliable object creation
  7. Implement business logic in your model classes (getters, methods)
0
likes
130
points
36
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package for network operations.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

cloud_firestore, firebase_core, flutter

More

Packages that depend on firebase_core_plus