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

A Flutter package for network operations.

example/lib/main.dart

/// Firebase Core Plus Example Application
/// 
/// This example demonstrates the basic usage of the firebase_core_plus package:
/// - Type-safe model implementation with InterfacePlus
/// - Simple CRUD operations with FirestorePlus
/// - Real-time streams for live data updates
/// - Modern Flutter UI with Material Design
/// 
/// ## Features Demonstrated
/// 
/// 1. **Cart Management**: Create and view shopping carts
/// 2. **Real-time Updates**: Live updates when data changes in Firestore
/// 
/// ## Firebase Setup
/// 
/// This example uses Firebase emulator for local development:
/// - No real Firebase project required
/// - Safe for testing and development
/// - Easy to set up and run locally
/// 
/// ## Model Architecture
/// 
/// The example uses the Cart model:
/// - **Cart**: Main collection with shopping cart data
/// 
/// The model implements InterfacePlus for type safety and serialization.

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

/// Main entry point of the application.
/// 
/// Initializes Firebase with emulator configuration for local development.
/// This allows testing without a real Firebase project.
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize Firebase with configuration
  // Note: These are fake values for emulator testing
  // In production, use your actual Firebase project configuration
  await Firebase.initializeApp(
    options: const FirebaseOptions(
      apiKey: "demo-api-key",
      authDomain: "demo-project.firebaseapp.com",
      projectId: "demo-project",
      storageBucket: "demo-project.appspot.com",
      messagingSenderId: "123456789",
      appId: "demo-app-id",
    ),
  );
  
  // Connect to Firebase emulator for local development
  // This allows testing without a real Firebase backend
  FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
  
  runApp(const MyApp());
}

/// Shopping cart model implementing InterfacePlus.
/// 
/// This model demonstrates:
/// - Proper InterfacePlus implementation
/// - Type-safe serialization/deserialization
/// - Business logic methods (getters)
/// - Safe type casting in withMap constructor
/// 
/// ## Properties
/// - **uid**: Document identifier (nullable for new documents)
/// - **name**: Cart name/description
/// - **price**: Total cart price
/// 
/// ## Business Logic
/// - **priceWithTVA**: Calculates price with 20% tax
/// - **isExpensive**: Determines if cart is expensive (>50€)
class Cart implements InterfacePlus {
  Cart({required this.uid, required this.name, required this.price});

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

  /// JSON serialization for Firestore storage.
  /// 
  /// Converts the Cart instance to a Map that can be stored in Firestore.
  /// Includes all necessary fields for reconstruction.
  @override
  Map<String, dynamic> get json => {
    'uid': uid,
    'name': name,
    'price': price,
  };

  /// Factory constructor for deserialization from Firestore data.
  /// 
  /// Handles safe type casting and provides default values for missing fields.
  /// This constructor is called by FirestorePlus when reading documents.
  static Cart withMap(Map<String, dynamic> map) => Cart(
    uid: map['uid'],
    name: map['name'] ?? 'Unnamed Cart',
    price: (map['price'] as num?)?.toDouble() ?? 0.0,
  );

  /// Calculates the price including 20% VAT.
  /// 
  /// This is an example of business logic that can be added to model classes.
  /// The calculation is performed on the client side for immediate feedback.
  double get priceWithTVA => price * 1.2;
  
  /// Determines if the cart is considered expensive (>50€).
  /// 
  /// Another example of business logic that can be encapsulated in the model.
  /// This can be used for UI decisions like showing warnings or special styling.
  bool get isExpensive => price > 50;
}



/// Main application widget.
/// 
/// Sets up the Material Design theme and navigation structure.
/// Uses a modern indigo color scheme for a professional appearance.
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FirestorePlus Demo',
      theme: ThemeData(
        primarySwatch: Colors.indigo,
        useMaterial3: true,
        cardTheme: CardThemeData(
          elevation: 4,
          margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
        ),
      ),
      home: const CartDemoPage(),
    );
  }
}

/// Main demo page showcasing FirestorePlus features.
/// 
/// This page demonstrates:
/// - Simple cart creation
/// - Real-time cart display
/// - Modern UI with cards and icons
class CartDemoPage extends StatefulWidget {
  const CartDemoPage({super.key});

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

/// State management for the cart demo page.
/// 
/// Manages:
/// - FirestorePlus instance for cart operations
/// - UI state and user interactions
class _CartDemoPageState extends State<CartDemoPage> {
  late final FirestorePlus<Cart> cartCollection;

  @override
  void initState() {
    super.initState();
    
    // Initialize FirestorePlus instance for cart operations
    // This instance will handle all cart-related Firestore operations
    cartCollection = FirestorePlus<Cart>.instance(
      tConstructor: Cart.withMap,
      path: 'carts',
    );
  }

  /// Adds a new cart to the collection.
  /// 
  /// Demonstrates:
  /// - Creating new documents with auto-generated IDs
  /// - Type-safe object creation
  /// - User feedback with SnackBar
  /// - Error handling
  Future<void> _addCart() async {
    try {
      // Create a new cart with a unique name based on timestamp
      final cart = Cart(
        uid: '', // Empty UID for new documents
        name: 'Cart ${DateTime.now().millisecondsSinceEpoch}',
        price: 19.99,
      );
      
      // Add the cart to Firestore and get the generated ID
      final id = await cartCollection.add(object: cart);
      
      // Show success message
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Cart added with ID: $id'),
          backgroundColor: Colors.green,
        ),
      );
    } catch (e) {
      // Handle errors and show user feedback
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Error adding cart: $e'),
          backgroundColor: Colors.red,
        ),
      );
    }
  }





  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FirestorePlus Demo'),
        backgroundColor: Colors.indigo,
        foregroundColor: Colors.white,
        elevation: 4,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            // Action buttons section
            _buildActionButtons(),
            const SizedBox(height: 24),
            
            // Real-time carts stream section
            _buildCartsStream(),
          ],
        ),
      ),
    );
  }

  /// Builds the action buttons section.
  /// 
  /// Contains button for:
  /// - Adding new carts
  Widget _buildActionButtons() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              'Actions',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 16),
            Center(
              child: ElevatedButton.icon(
                onPressed: _addCart,
                icon: const Icon(Icons.add_shopping_cart),
                label: const Text('Add Cart'),
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.green,
                  foregroundColor: Colors.white,
                  padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 16),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// Builds the real-time carts stream section.
  /// 
  /// Displays:
  /// - Live updates of all carts
  /// - Cart information with business logic
  /// - Visual indicators for expensive carts
  /// - Loading and empty states
  Widget _buildCartsStream() {
    return Expanded(
      child: Card(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Real-time Carts Stream:',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 16),
              Expanded(
                child: StreamBuilder<List<Cart>>(
                  stream: cartCollection.streams,
                  builder: (context, snapshot) {
                    // Handle loading state
                    if (snapshot.connectionState == ConnectionState.waiting) {
                      return const Center(
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            CircularProgressIndicator(),
                            SizedBox(height: 16),
                            Text('Loading carts...'),
                          ],
                        ),
                      );
                    }
                    
                    // Handle error state
                    if (snapshot.hasError) {
                      return Center(
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            const Icon(
                              Icons.error_outline,
                              size: 64,
                              color: Colors.red,
                            ),
                            const SizedBox(height: 16),
                            Text(
                              'Error: ${snapshot.error}',
                              style: const TextStyle(color: Colors.red),
                              textAlign: TextAlign.center,
                            ),
                          ],
                        ),
                      );
                    }
                    
                    // Handle empty state
                    final carts = snapshot.data ?? [];
                    if (carts.isEmpty) {
                      return const Center(
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Icon(
                              Icons.shopping_cart_outlined,
                              size: 64,
                              color: Colors.grey,
                            ),
                            SizedBox(height: 16),
                            Text(
                              'No carts available.\nAdd a cart to get started!',
                              style: TextStyle(
                                fontSize: 16,
                                color: Colors.grey,
                              ),
                              textAlign: TextAlign.center,
                            ),
                          ],
                        ),
                      );
                    }
                    
                    // Display carts list
                    return ListView.builder(
                      itemCount: carts.length,
                      itemBuilder: (context, index) {
                        final cart = carts[index];
                        return Card(
                          margin: const EdgeInsets.symmetric(vertical: 4),
                          child: ListTile(
                            leading: CircleAvatar(
                              backgroundColor: cart.isExpensive 
                                  ? Colors.orange 
                                  : Colors.green,
                              child: Icon(
                                cart.isExpensive 
                                    ? Icons.warning 
                                    : Icons.check_circle,
                                color: Colors.white,
                              ),
                            ),
                            title: Text(
                              cart.name,
                              style: const TextStyle(fontWeight: FontWeight.bold),
                            ),
                            subtitle: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Text('Price: ${cart.price.toStringAsFixed(2)} €'),
                                Text(
                                  'TTC: ${cart.priceWithTVA.toStringAsFixed(2)} €',
                                  style: const TextStyle(
                                    fontWeight: FontWeight.w500,
                                    color: Colors.blue,
                                  ),
                                ),
                              ],
                            ),
                            trailing: cart.isExpensive
                                ? const Chip(
                                    label: Text('Expensive'),
                                    backgroundColor: Colors.orange,
                                    labelStyle: TextStyle(color: Colors.white),
                                  )
                                : const Chip(
                                    label: Text('Affordable'),
                                    backgroundColor: Colors.green,
                                    labelStyle: TextStyle(color: Colors.white),
                                  ),
                          ),
                        );
                      },
                    );
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
0
likes
125
points
38
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