├── README.md
├── lib
├── cartmodel.dart
├── cartpage.dart
├── home.dart
└── main.dart
├── pubspec.lock
├── pubspec.yaml
├── screenshot
├── cart.jpg
└── home.jpg
└── shopping.iml
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Shopping Cart
2 | A Shopping Cart (Ecommerce) using Flutter scoped_model
3 |
4 | ### Dependencies
5 |
6 | ```
7 | scoped_model: ^1.0.1
8 | ```
9 |
10 | ### Flutter Shopping Cart Features
11 |
12 | - GridView.builder for displaying Products List
13 | - ListView.builder for cart
14 | - Add Product to Cart
15 | - Remove Product from Cart
16 | - Increase & Decrease Product Qty
17 | - Remove Produt when Product Qty == 0
18 | - Calculate Product Price (Qty * price)
19 | - Calculate overall pricing
20 |
21 |
22 | ### Screenshots
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/lib/cartmodel.dart:
--------------------------------------------------------------------------------
1 | import 'package:scoped_model/scoped_model.dart';
2 |
3 | class CartModel extends Model {
4 | List cart = [];
5 | double totalCartValue = 0;
6 |
7 | int get total => cart.length;
8 |
9 | void addProduct(product) {
10 | int index = cart.indexWhere((i) => i.id == product.id);
11 | print(index);
12 | if (index != -1)
13 | updateProduct(product, product.qty + 1);
14 | else {
15 | cart.add(product);
16 | calculateTotal();
17 | notifyListeners();
18 | }
19 | }
20 |
21 | void removeProduct(product) {
22 | int index = cart.indexWhere((i) => i.id == product.id);
23 | cart[index].qty = 1;
24 | cart.removeWhere((item) => item.id == product.id);
25 | calculateTotal();
26 | notifyListeners();
27 | }
28 |
29 | void updateProduct(product, qty) {
30 | int index = cart.indexWhere((i) => i.id == product.id);
31 | cart[index].qty = qty;
32 | if (cart[index].qty == 0)
33 | removeProduct(product);
34 |
35 | calculateTotal();
36 | notifyListeners();
37 | }
38 |
39 | void clearCart() {
40 | cart.forEach((f) => f.qty = 1);
41 | cart = [];
42 | notifyListeners();
43 | }
44 |
45 | void calculateTotal() {
46 | totalCartValue = 0;
47 | cart.forEach((f) {
48 | totalCartValue += f.price * f.qty;
49 | });
50 | }
51 | }
52 |
53 | class Product {
54 | int id;
55 | String title;
56 | String imgUrl;
57 | double price;
58 | int qty;
59 |
60 | Product({this.id, this.title, this.price, this.qty, this.imgUrl});
61 | }
62 |
--------------------------------------------------------------------------------
/lib/cartpage.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:scoped_model/scoped_model.dart';
3 | import 'package:shopping/cartmodel.dart';
4 |
5 | class CartPage extends StatefulWidget {
6 | @override
7 | State createState() {
8 | return _CartPageState();
9 | }
10 | }
11 |
12 | class _CartPageState extends State {
13 | @override
14 | Widget build(BuildContext context) {
15 | // TODO: implement build
16 | return Scaffold(
17 | appBar: AppBar(
18 | backgroundColor: Colors.indigo,
19 | title: Text("Cart"),
20 | actions: [
21 | FlatButton(
22 | child: Text(
23 | "Clear",
24 | style: TextStyle(color: Colors.white),
25 | ),
26 | onPressed: () => ScopedModel.of(context).clearCart())
27 | ],
28 | ),
29 | body: ScopedModel.of(context, rebuildOnChange: true)
30 | .cart
31 | .length ==
32 | 0
33 | ? Center(
34 | child: Text("No items in Cart"),
35 | )
36 | : Container(
37 | padding: EdgeInsets.all(8.0),
38 | child: Column(children: [
39 | Expanded(
40 | child: ListView.builder(
41 | itemCount: ScopedModel.of(context,
42 | rebuildOnChange: true)
43 | .total,
44 | itemBuilder: (context, index) {
45 | return ScopedModelDescendant(
46 | builder: (context, child, model) {
47 | return ListTile(
48 | title: Text(model.cart[index].title),
49 | subtitle: Text(model.cart[index].qty.toString() +
50 | " x " +
51 | model.cart[index].price.toString() +
52 | " = " +
53 | (model.cart[index].qty *
54 | model.cart[index].price)
55 | .toString()),
56 | trailing: Row(
57 | mainAxisSize: MainAxisSize.min,
58 | children: [
59 | IconButton(
60 | icon: Icon(Icons.add),
61 | onPressed: () {
62 | model.updateProduct(model.cart[index],
63 | model.cart[index].qty + 1);
64 | // model.removeProduct(model.cart[index]);
65 | },
66 | ),
67 | IconButton(
68 | icon: Icon(Icons.remove),
69 | onPressed: () {
70 | model.updateProduct(model.cart[index],
71 | model.cart[index].qty - 1);
72 | // model.removeProduct(model.cart[index]);
73 | },
74 | ),
75 | ]),
76 | );
77 | },
78 | );
79 | },
80 | ),
81 | ),
82 | Container(
83 | padding: EdgeInsets.all(8.0),
84 | child: Text(
85 | "Total: \$ " +
86 | ScopedModel.of(context,
87 | rebuildOnChange: true)
88 | .totalCartValue
89 | .toString() +
90 | "",
91 | style: TextStyle(
92 | fontSize: 24.0, fontWeight: FontWeight.bold),
93 | )),
94 | SizedBox(
95 | width: double.infinity,
96 | child: RaisedButton(
97 | color: Colors.yellow[900],
98 | textColor: Colors.white,
99 | elevation: 0,
100 | child: Text("BUY NOW"),
101 | onPressed: () {},
102 | ))
103 | ])));
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/lib/home.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:scoped_model/scoped_model.dart';
3 | import 'package:shopping/cartmodel.dart';
4 |
5 | class HomePage extends StatelessWidget {
6 | List _products = [
7 | Product(
8 | id: 1,
9 | title: "Apple",
10 | price: 20.0,
11 | imgUrl: "https://img.icons8.com/plasticine/2x/apple.png",
12 | qty: 1),
13 | Product(
14 | id: 2,
15 | title: "Banana",
16 | price: 40.0,
17 | imgUrl: "https://img.icons8.com/cotton/2x/banana.png",
18 | qty: 1),
19 | Product(
20 | id: 3,
21 | title: "Orange",
22 | price: 20.0,
23 | imgUrl: "https://img.icons8.com/cotton/2x/orange.png",
24 | qty: 1),
25 | Product(
26 | id: 4,
27 | title: "Melon",
28 | price: 40.0,
29 | imgUrl: "https://img.icons8.com/cotton/2x/watermelon.png",
30 | qty: 1),
31 | Product(
32 | id: 5,
33 | title: "Avocado",
34 | price: 25.0,
35 | imgUrl: "https://img.icons8.com/cotton/2x/avocado.png",
36 | qty: 1),
37 | ];
38 |
39 | @override
40 | Widget build(BuildContext context) {
41 | return Scaffold(
42 | backgroundColor: Colors.indigo[50],
43 | appBar: AppBar(
44 | backgroundColor: Colors.indigo,
45 | title: Text("Home"),
46 | actions: [
47 | IconButton(
48 | icon: Icon(Icons.shopping_cart),
49 | onPressed: () => Navigator.pushNamed(context, '/cart'),
50 | )
51 | ],
52 | ),
53 | body:
54 | GridView.builder(
55 | padding: EdgeInsets.all(8.0),
56 | itemCount: _products.length,
57 | gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 8, crossAxisSpacing: 8, childAspectRatio: 0.8),
58 | itemBuilder: (context, index){
59 | return ScopedModelDescendant(
60 | builder: (context, child, model) {
61 | return Card( child: Column( children: [
62 | Image.network(_products[index].imgUrl, height: 120, width: 120,),
63 | Text(_products[index].title, style: TextStyle(fontWeight: FontWeight.bold),),
64 | Text("\$"+_products[index].price.toString()),
65 | OutlineButton(
66 | child: Text("Add"),
67 | onPressed: () => model.addProduct(_products[index]))
68 | ]));
69 | });
70 | },
71 | ),
72 |
73 | // ListView.builder(
74 | // itemExtent: 80,
75 | // itemCount: _products.length,
76 | // itemBuilder: (context, index) {
77 | // return ScopedModelDescendant(
78 | // builder: (context, child, model) {
79 | // return ListTile(
80 | // leading: Image.network(_products[index].imgUrl),
81 | // title: Text(_products[index].title),
82 | // subtitle: Text("\$"+_products[index].price.toString()),
83 | // trailing: OutlineButton(
84 | // child: Text("Add"),
85 | // onPressed: () => model.addProduct(_products[index])));
86 | // });
87 | // },
88 | // ),
89 |
90 | );
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:scoped_model/scoped_model.dart';
3 | import 'package:shopping/cartmodel.dart';
4 | import 'package:shopping/cartpage.dart';
5 | import 'package:shopping/home.dart';
6 | import 'package:shopping/main.dart';
7 |
8 | void main() => runApp(MyApp(
9 | model: CartModel(),
10 | ));
11 |
12 |
13 | class MyApp extends StatelessWidget{
14 |
15 | final CartModel model;
16 |
17 | const MyApp({Key key, @required this.model}) : super(key: key);
18 |
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | // TODO: implement build
23 | return ScopedModel(
24 | model: model,
25 | child: MaterialApp(
26 | debugShowCheckedModeBanner: false,
27 | title: 'Shopping Cart',
28 | home: HomePage(),
29 | routes: {'/cart': (context) => CartPage()},
30 | ),
31 | );
32 | }
33 | }
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile
3 | packages:
4 | async:
5 | dependency: transitive
6 | description:
7 | name: async
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "2.1.0"
11 | boolean_selector:
12 | dependency: transitive
13 | description:
14 | name: boolean_selector
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "1.0.4"
18 | charcode:
19 | dependency: transitive
20 | description:
21 | name: charcode
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "1.1.2"
25 | collection:
26 | dependency: transitive
27 | description:
28 | name: collection
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "1.14.11"
32 | cupertino_icons:
33 | dependency: "direct main"
34 | description:
35 | name: cupertino_icons
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "0.1.2"
39 | flutter:
40 | dependency: "direct main"
41 | description: flutter
42 | source: sdk
43 | version: "0.0.0"
44 | flutter_test:
45 | dependency: "direct dev"
46 | description: flutter
47 | source: sdk
48 | version: "0.0.0"
49 | matcher:
50 | dependency: transitive
51 | description:
52 | name: matcher
53 | url: "https://pub.dartlang.org"
54 | source: hosted
55 | version: "0.12.5"
56 | meta:
57 | dependency: transitive
58 | description:
59 | name: meta
60 | url: "https://pub.dartlang.org"
61 | source: hosted
62 | version: "1.1.6"
63 | path:
64 | dependency: transitive
65 | description:
66 | name: path
67 | url: "https://pub.dartlang.org"
68 | source: hosted
69 | version: "1.6.2"
70 | pedantic:
71 | dependency: transitive
72 | description:
73 | name: pedantic
74 | url: "https://pub.dartlang.org"
75 | source: hosted
76 | version: "1.5.0"
77 | quiver:
78 | dependency: transitive
79 | description:
80 | name: quiver
81 | url: "https://pub.dartlang.org"
82 | source: hosted
83 | version: "2.0.2"
84 | scoped_model:
85 | dependency: "direct main"
86 | description:
87 | name: scoped_model
88 | url: "https://pub.dartlang.org"
89 | source: hosted
90 | version: "1.0.1"
91 | sky_engine:
92 | dependency: transitive
93 | description: flutter
94 | source: sdk
95 | version: "0.0.99"
96 | source_span:
97 | dependency: transitive
98 | description:
99 | name: source_span
100 | url: "https://pub.dartlang.org"
101 | source: hosted
102 | version: "1.5.5"
103 | stack_trace:
104 | dependency: transitive
105 | description:
106 | name: stack_trace
107 | url: "https://pub.dartlang.org"
108 | source: hosted
109 | version: "1.9.3"
110 | stream_channel:
111 | dependency: transitive
112 | description:
113 | name: stream_channel
114 | url: "https://pub.dartlang.org"
115 | source: hosted
116 | version: "2.0.0"
117 | string_scanner:
118 | dependency: transitive
119 | description:
120 | name: string_scanner
121 | url: "https://pub.dartlang.org"
122 | source: hosted
123 | version: "1.0.4"
124 | term_glyph:
125 | dependency: transitive
126 | description:
127 | name: term_glyph
128 | url: "https://pub.dartlang.org"
129 | source: hosted
130 | version: "1.1.0"
131 | test_api:
132 | dependency: transitive
133 | description:
134 | name: test_api
135 | url: "https://pub.dartlang.org"
136 | source: hosted
137 | version: "0.2.4"
138 | typed_data:
139 | dependency: transitive
140 | description:
141 | name: typed_data
142 | url: "https://pub.dartlang.org"
143 | source: hosted
144 | version: "1.1.6"
145 | vector_math:
146 | dependency: transitive
147 | description:
148 | name: vector_math
149 | url: "https://pub.dartlang.org"
150 | source: hosted
151 | version: "2.0.8"
152 | sdks:
153 | dart: ">=2.2.0 <3.0.0"
154 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: shopping
2 | description: A new Flutter project.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # In Android, build-name is used as versionName while build-number used as versionCode.
10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning
11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
12 | # Read more about iOS versioning at
13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
14 | version: 1.0.0+1
15 |
16 | environment:
17 | sdk: ">=2.1.0 <3.0.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 | scoped_model: ^1.0.1
23 |
24 | # The following adds the Cupertino Icons font to your application.
25 | # Use with the CupertinoIcons class for iOS style icons.
26 | cupertino_icons: ^0.1.2
27 |
28 | dev_dependencies:
29 | flutter_test:
30 | sdk: flutter
31 |
32 |
33 | # For information on the generic Dart part of this file, see the
34 | # following page: https://www.dartlang.org/tools/pub/pubspec
35 |
36 | # The following section is specific to Flutter.
37 | flutter:
38 |
39 | # The following line ensures that the Material Icons font is
40 | # included with your application, so that you can use the icons in
41 | # the material Icons class.
42 | uses-material-design: true
43 |
44 | # To add assets to your application, add an assets section, like this:
45 | # assets:
46 | # - images/a_dot_burr.jpeg
47 | # - images/a_dot_ham.jpeg
48 |
49 | # An image asset can refer to one or more resolution-specific "variants", see
50 | # https://flutter.dev/assets-and-images/#resolution-aware.
51 |
52 | # For details regarding adding assets from package dependencies, see
53 | # https://flutter.dev/assets-and-images/#from-packages
54 |
55 | # To add custom fonts to your application, add a fonts section here,
56 | # in this "flutter" section. Each entry in this list should have a
57 | # "family" key with the font family name, and a "fonts" key with a
58 | # list giving the asset and other descriptors for the font. For
59 | # example:
60 | # fonts:
61 | # - family: Schyler
62 | # fonts:
63 | # - asset: fonts/Schyler-Regular.ttf
64 | # - asset: fonts/Schyler-Italic.ttf
65 | # style: italic
66 | # - family: Trajan Pro
67 | # fonts:
68 | # - asset: fonts/TrajanPro.ttf
69 | # - asset: fonts/TrajanPro_Bold.ttf
70 | # weight: 700
71 | #
72 | # For details regarding fonts from package dependencies,
73 | # see https://flutter.dev/custom-fonts/#from-packages
74 |
--------------------------------------------------------------------------------
/screenshot/cart.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codesundar/flutter-shopping-cart/9e3ed7360f190b6397159178fa45badfaa6985de/screenshot/cart.jpg
--------------------------------------------------------------------------------
/screenshot/home.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codesundar/flutter-shopping-cart/9e3ed7360f190b6397159178fa45badfaa6985de/screenshot/home.jpg
--------------------------------------------------------------------------------
/shopping.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------