Menu
CoddyTech
flag Ar iconالعربيةdown icon

عربة التسوق: الإجمالي

جزء من قسم إدارة الحالة في رحلة Flutter على Coddy. الدرس 25 من 27.

تحتاج شاشة عربة التسوق إلى إجمالي. والإجمالي ليس بيانات جديدة؛ فهو ناتج عمّا يوجد في العربة. لذلك لا يُخزَّن في أي مكان. إنه موفّر يراقب العربة ويجمع الأسعار باستخدام fold:

final totalProvider = Provider((ref) {
  final cart = ref.watch(cartProvider);
  return cart.fold(0.0, (sum, product) => sum + product.price);
});

لأنه يراقب العربة، يُعاد حساب الإجمالي كلما تغيّرت العربة، وكل عنصر واجهة يراقب الإجمالي يعرض المبلغ الجديد.

اعرضه أسفل القائمة. تقبل خانة bottomNavigationBar في Scaffold أي عنصر واجهة وتُبقيه في أسفل الشاشة، تحت القائمة، حتى عند تمرير القائمة.

challenge icon

التحدي

متوسط

اعرض الإجمالي في شاشة عربة التسوق:

  • أضف totalProvider يراقب cartProvider ويجمع الأسعار.
  • في شاشة عربة التسوق، اعرض Total: $2.75 (بمنزلتين عشريتين) في bottomNavigationBar الخاص بـ Scaffold، مع إضافة بعض الحشو.

جرّب بنفسك

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class Product {
  const Product(this.name, this.price);

  final String name;
  final double price;
}

const products = [
  Product('Apple', 0.5),
  Product('Bread', 2.25),
  Product('Cheese', 4),
  Product('Milk', 1.2),
];

class Cart extends Notifier<List<Product>> {
  @override
  List<Product> build() => [];

  void add(Product product) {
    state = [...state, product];
  }
}

final cartProvider = NotifierProvider<Cart, List<Product>>(Cart.new);

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ShopPage(),
    );
  }
}

class ShopPage extends ConsumerWidget {
  const ShopPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cart = ref.watch(cartProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Shop'),
        actions: [
          IconButton(
            icon: Badge(
              label: Text('${cart.length}'),
              isLabelVisible: cart.isNotEmpty,
              child: const Icon(Icons.shopping_cart),
            ),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => const CartScreen()),
              );
            },
          ),
        ],
      ),
      body: ListView(
        children: [
          for (final product in products)
            ListTile(
              title: Text(product.name),
              subtitle: Text('\$${product.price.toStringAsFixed(2)}'),
              trailing: IconButton(
                icon: const Icon(Icons.add_shopping_cart),
                onPressed: () {
                  ref.read(cartProvider.notifier).add(product);
                },
              ),
            ),
        ],
      ),
    );
  }
}

class CartScreen extends ConsumerWidget {
  const CartScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cart = ref.watch(cartProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('Your cart')),
      body: cart.isEmpty
          ? const Center(child: Text('Your cart is empty'))
          : ListView(
              children: [
                for (final product in cart)
                  ListTile(
                    title: Text(product.name),
                    trailing: Text('\$${product.price.toStringAsFixed(2)}'),
                  ),
              ],
            ),
    );
  }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس إدارة الحالة

تدرّب بنفسك: مترجم Flutter عبر الإنترنت