I keep on getting this problem:
Unhandled Exception: Error: Could not find the correct Provider above this HomeScreen Widget
Since I am trying to implement Cart Item Counter, there is this bug.
Here is my code:
Main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
sharedPreferences = await SharedPreferences.getInstance();
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (c) => CartItemCounter()),
ChangeNotifierProvider(create: (c) => TotalAmount()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Users App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MySplashScreen(),
),
);
}
}
Below is my App Bar, This is where i send users to Cart:
class MyAppBar extends StatefulWidget with PreferredSizeWidget {
final PreferredSizeWidget? bottom;
final String? sellerUID;
MyAppBar({this.bottom, this.sellerUID});
@override
_MyAppBarState createState() => _MyAppBarState();
@override
Size get preferredSize => bottom == null
? Size(56, AppBar().preferredSize.height)
: Size(56, 80 AppBar().preferredSize.height);
}
class _MyAppBarState extends State<MyAppBar> {
@override
Widget build(BuildContext context) {
return AppBar(
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.cyan,
Colors.amber,
],
begin: FractionalOffset(0.0, 0.0),
end: FractionalOffset(1.0, 0.0),
stops: [0.0, 1.0],
tileMode: TileMode.clamp,
)),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
title: const Text(
"iFood",
style: TextStyle(fontSize: 45, fontFamily: "Signatra"),
),
centerTitle: true,
automaticallyImplyLeading: true,
actions: [
Stack(
children: [
IconButton(
icon: const Icon(
Icons.shopping_cart,
color: Colors.cyan,
),
onPressed: () {
//send user to cart screen
Navigator.push(
context,
MaterialPageRoute(
builder: (c) =>
CartScreen(sellerUID: widget.sellerUID)));
},
),
Positioned(
child: Stack(
children: [
const Icon(
Icons.brightness_1,
size: 20.0,
color: Colors.green,
),
Positioned(
top: 3,
right: 4,
child: Center(
child: Consumer<CartItemCounter>(
builder: (context, counter, c) {
return Text(
counter.count.toString(),
style: const TextStyle(
color: Colors.white, fontSize: 12),
);
},
),
),
),
],
),
),
],
),
],
);
}
}
Following is My Cart Screen:
I want to display cart items with quantity number
class CartScreen extends StatefulWidget {
final String? sellerUID;
CartScreen({this.sellerUID});
@override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen> {
List<int>? separateItemQuantityList;
num totalAmount = 0;
@override
void initState() {
super.initState();
totalAmount = 0;
Provider.of<TotalAmount>(context, listen: false).displayTotalAmount(0);
separateItemQuantityList = separateItemQuantities();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.cyan,
Colors.amber,
],
begin: FractionalOffset(0.0, 0.0),
end: FractionalOffset(1.0, 0.0),
stops: [0.0, 1.0],
tileMode: TileMode.clamp,
)),
),
leading: IconButton(
icon: const Icon(Icons.clear_all),
onPressed: () {
clearCartNow(context);
},
),
title: const Text(
"iFood",
style: TextStyle(fontSize: 45, fontFamily: "Signatra"),
),
centerTitle: true,
automaticallyImplyLeading: true,
actions: [
Stack(
children: [
IconButton(
icon: const Icon(
Icons.shopping_cart,
color: Colors.cyan,
),
onPressed: () {
print("clicked");
},
),
Positioned(
child: Stack(
children: [
const Icon(
Icons.brightness_1,
size: 20.0,
color: Colors.green,
),
Positioned(
top: 3,
right: 4,
child: Center(
child: Consumer<CartItemCounter>(
builder: (context, counter, c) {
return Text(
counter.count.toString(),
style: const TextStyle(
color: Colors.white, fontSize: 12),
);
},
),
),
),
],
),
),
],
),
],
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
const SizedBox(
width: 10,
),
Align(
alignment: Alignment.bottomLeft,
child: FloatingActionButton.extended(
label: const Text(
"Clear Cart",
style: TextStyle(fontSize: 16),
),
backgroundColor: Colors.cyan,
icon: const Icon(Icons.clear_all),
onPressed: () {
clearCartNow(context);
Navigator.push(context,
MaterialPageRoute(builder: (c) => const MySplashScreen()));
Fluttertoast.showToast(msg: "Cart has been cleared.");
},
),
),
Align(
alignment: Alignment.bottomLeft,
child: FloatingActionButton.extended(
label: const Text(
"Check Out",
style: TextStyle(fontSize: 16),
),
backgroundColor: Colors.cyan,
icon: const Icon(Icons.navigate_next),
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (c) => AddressScreen(
// totalAmount: totalAmount.toDouble(),
// sellerUID: widget.sellerUID,
// ),
// ),
// );
},
),
),
],
),
body: CustomScrollView(
slivers: [
//overall total amount
SliverPersistentHeader(
pinned: true, delegate: TextWidgetHeader(title: "My Cart List")),
SliverToBoxAdapter(
child: Consumer2<TotalAmount, CartItemCounter>(
builder: (context, amountProvider, cartProvider, c) {
return Padding(
padding: const EdgeInsets.all(8),
child: Center(
child: cartProvider.count == 0
? Container()
: Text(
"Total Price: " amountProvider.tAmount.toString(),
style: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
),
);
}),
),
//display cart items with quantity number
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("items")
.where("itemID", whereIn: separateItemIDs())
.orderBy("publishedDate", descending: true)
.snapshots(),
builder: (context, snapshot) {
return !snapshot.hasData
? SliverToBoxAdapter(
child: Center(
child: circularProgress(),
),
)
: snapshot.data!.docs.length == 0
? //startBuildingCart()
Container()
: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
Items model = Items.fromJson(
snapshot.data!.docs[index].data()!
as Map<String, dynamic>,
);
if (index == 0) {
totalAmount = 0;
totalAmount = totalAmount
(model.price! *
separateItemQuantityList![index]);
} else {
totalAmount = totalAmount
(model.price! *
separateItemQuantityList![index]);
}
if (snapshot.data!.docs.length - 1 == index) {
WidgetsBinding.instance
.addPostFrameCallback((timeStamp) {
Provider.of<TotalAmount>(context,
listen: false)
.displayTotalAmount(
totalAmount.toDouble());
});
}
return CartItemDesign(
model: model,
context: context,
quanNumber: separateItemQuantityList![index],
);
},
childCount: snapshot.hasData
? snapshot.data!.docs.length
: 0,
),
);
},
),
],
),
);
}
}
CodePudding user response:
It's hard to tell what is the problem without looking at the whole source code.
My guess is that you need to pass the ChangeNotifierProvider instance across routes (basically whenever you do Navigator.push()
).
Check out this answer.
CodePudding user response:
When passing ChangeNotifierProvider in main
Pass it like this
ChangeNotifierProvider(
create : (context) => CartItemCounter(),
child : CartScreen (), // screen where you want to access the Provider
),