Reputation: 21
The items maps don't take any new values after I call the addItem() method. Here is my provider:
import 'package:flutter/material.dart';
class CartItem {
final String id;
final String title;
final int quantity;
final double price;
CartItem({
required this.id,
required this.title,
required this.quantity,
required this.price,
});
}
class Cart with ChangeNotifier {
Map<String, CartItem> _items = {};
Map<String, CartItem> get items {
return {..._items};
}
int get itemCount {
return items.length;
}
void addItem({
required String productId,
required double price,
required String title,
}) {
/*check if the items already exist in cart
else add the item in cart with quantity one.*/
if (items.containsKey(productId)) {
// update the quantity
items.update(
productId,
(existingCartItem) => CartItem(
id: existingCartItem.id,
title: existingCartItem.title,
quantity: existingCartItem.quantity + 1,
price: existingCartItem.price,
));
} else {
// add the new item to cart
items.putIfAbsent(
productId,
() => CartItem(
id: DateTime.now().toString(),
title: title,
price: price,
quantity: 1,
),
);
}
// notifying all the listners to update on changes.
print(items);
notifyListeners();
}
}
Here is the Listener:
the badge() is an stateless widget for displaying the shopping cart icon with the number of items in the cart.
This is the badge() (at the top right corner.)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../widgets/products_grid.dart';
import '../providers/cart.dart';
import '../widgets/badge.dart';
enum FilterOptions {
favorite,
all,
}
class ProductOverviewScreen extends StatefulWidget {
@override
State<ProductOverviewScreen> createState() => _ProductOverviewScreenState();
}
class _ProductOverviewScreenState extends State<ProductOverviewScreen> {
var showFavs = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My Shop'),
centerTitle: true,
actions: [
PopupMenuButton(
onSelected: (selectedValue) => setState(() {
if (selectedValue == FilterOptions.favorite) {
showFavs = true;
} else {
showFavs = false;
}
}),
itemBuilder: (context) => [
const PopupMenuItem(
value: FilterOptions.favorite,
child: Text("Only Favorites"),
),
const PopupMenuItem(
value: FilterOptions.all,
child: Text("Show All"),
),
],
),
// top shopping card icon button
Consumer<Cart>(
builder: ((context, cart, ch) => Badge(
value: cart.itemCount.toString(),
child: ch as Widget,
)),
// taking this out of the builder method as it doesn't need to be re-rendered.
child: IconButton(
icon: const Icon(Icons.shopping_cart),
onPressed: () {},
),
)
],
),
body: ProductsGrid(showFavs),
);
}
}
This is the class where I call the addItem method: The call is from the icon button at the trailing widget of the gridTile.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../screens/product_detail_screen.dart';
import '../providers/product.dart';
import '../providers/cart.dart';
class ProductItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final product = Provider.of<Product>(context, listen: false);
final cart = Provider.of<Cart>(context, listen: false);
return ClipRRect(
borderRadius: BorderRadius.circular(12),
child: GestureDetector(
onTap: () {
Navigator.of(context).pushNamed(
ProductsDetailScreen.routeName,
arguments: product.id,
);
},
child: GridTile(
footer: GridTileBar(
backgroundColor: Colors.black87,
leading: Consumer<Product>(
builder: (context, value, _) => IconButton(
icon: Icon(
product.isFavorite ? Icons.favorite : Icons.favorite_border,
color: Colors.deepOrange,
),
onPressed: () {
product.toggleFavorite();
},
),
),
title: Text(
product.title,
textAlign: TextAlign.center,
),
trailing: IconButton(
icon: Icon(
Icons.shopping_cart_outlined,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
cart.addItem(
productId: product.id,
price: product.price,
title: product.title);
},
),
),
child: Image.network(
product.imageUrl,
fit: BoxFit.cover,
),
),
),
);
}
}
And here is the main.dart file (in case needed) I am using multiprovider:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shop/providers/cart.dart';
import 'package:shop/screens/product_detail_screen.dart';
import './providers/products.dart';
import './screens/product_overview_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => Products(),
),
ChangeNotifierProvider(
create: (context) => Cart(),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'My Shop',
theme: ThemeData(
primarySwatch: Colors.purple,
colorScheme: const ColorScheme.light(secondary: Colors.deepOrange),
fontFamily: 'Lato',
),
home: ProductOverviewScreen(),
routes: {
ProductsDetailScreen.routeName: (context) =>
const ProductsDetailScreen(),
},
),
);
}
}
I tried clicking the shopping cart icon button. This is the debugger console:
Restarted application in 413ms.
2 I/flutter ( 5850): {}
2 because I clicked the shopping cart button twice. The 2 would increment by one as I click the shopping cart button. But items are not being added to the items map. The number on the shopping cart icon on the screen remains zero.
I expect to see the number in the shopping cart number update as the products get in the items map.
Upvotes: 0
Views: 303