عربة التسوق: إتمام الشراء
جزء من قسم إدارة الحالة في رحلة Flutter على Coddy. الدرس 27 من 27.
الجزء الأخير هو إتمام الشراء. تنفّذ نقرة واحدة ثلاثة أشياء: تُفرَّغ عربة التسوق، وتؤكد رسالة الطلب، ويعود المتسوق إلى المتجر، حيث تختفي الشارة.
التفريغ طريقة أخرى في المُخطِر، وتعيّن قائمة جديدة فارغة:
void clear() {
state = [];
}لا معنى لإتمام الشراء إذا لم يكن في العربة شيء، لذا اجعل الزر باللون الرمادي. الزر الذي تكون قيمة onPressed فيه null لا يمكن الضغط عليه:
onPressed: cart.isEmpty ? null : () { ... },تأمّل ما بنيته: شاشتان، وشارة، وإجمالي، كلها تقرأ من عربة واحدة، من دون تمرير أي قيمة من شاشة إلى أخرى. هذا هو تدبير الحالة.
التحدي
متوسطأسفل الإجمالي في شاشة سلة التسوق، أضف زر Check out:
- يكون معطّلًا عندما تكون السلة فارغة.
- عند الضغط عليه، يُفرغ السلة باستخدام الطريقة الجديدة
clear()، ويعرضSnackBarيقولOrder placed!، ثم يعود إلى المتجر.
جرّب بنفسك
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];
}
void removeAt(int index) {
final copy = [...state];
copy.removeAt(index);
state = copy;
}
}
final cartProvider = NotifierProvider<Cart, List<Product>>(Cart.new);
final totalProvider = Provider((ref) {
final cart = ref.watch(cartProvider);
return cart.fold(0.0, (sum, product) => sum + product.price);
});
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);
final total = ref.watch(totalProvider);
return Scaffold(
appBar: AppBar(title: const Text('Your cart')),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(24),
child: Text(
'Total: \$${total.toStringAsFixed(2)}',
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
),
body: cart.isEmpty
? const Center(child: Text('Your cart is empty'))
: ListView(
children: [
for (var i = 0; i < cart.length; i++)
ListTile(
title: Text(cart[i].name),
subtitle: Text('\$${cart[i].price.toStringAsFixed(2)}'),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
ref.read(cartProvider.notifier).removeAt(i);
},
),
),
],
),
);
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس إدارة الحالة
2Dart للنماذج
الطرق في الأصناف الخاصة بكالمُعرِّفات في أصنافكاجعل أحد الحقول خاصًااجمع عناصر قائمة باستخدام fold5مشروع: عربة التسوق
عربة التسوق: الإضافة إلى العربةعربة التسوق: شارة العددتدرّب بنفسك: مترجم Flutter عبر الإنترنت