Skip to content

TheAvtarSingh/Catelog_Application_Flutter

Repository files navigation

Lets_Learn_Flutter_2023

following this Video To Craete A Catelog Application https://www.youtube.com/watch?v=j-LOab_PzzU&ab_channel=Codepur

use flutter create catelog_application and create Flutter Project

image

In main.dart delete everything and make a stateless widget MyApp()

image

Step 1 : Add MaterialApp() in home: Add Scaffold() add appbar : AppBar() in body : Center(child:Text("Add Text"));

image

Add A Drawer

image

Output

image

Splitiing Files

Make Folder

image

Add Code

image

Import in Main.dart import 'pages/HomePage.dart';;

image

Use Function

image

Adding Theme

      // Give app Dark Theme based on System Theme
      // Setting code if application gets theme
      themeMode: ThemeMode.dark,
      theme: ThemeData(brightness: Brightness.dark),
      

image

or

      // themeMode: ThemeMode.dark,
      theme: ThemeData(brightness: Brightness.dark),

image

Output

image

Adding Light Theme

image

      // Giving System Theme
      // Specify Theme
      // use brightness: Brightness.dark for Dark Theme
      // primarySwatch : adjust by color for Light Theme
      themeMode: ThemeMode.dark,
      theme: ThemeData(primarySwatch: Colors.deepPurple),
      

image

If We use Both -- Brightness.dark will override it

image

image

Using Routes - For Multiple Pages

Delete home Tag image

and Specify in the Routes

image

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Text(
          "This is Login Page",
          style: TextStyle(
              fontSize: 20, fontWeight: FontWeight.bold, color: Colors.blue),
        ),
      ),
    );
  }
}

image

Creating a Login Page

Adding an Image

  1. Add Text Image use unDraw for image

Specify in PUBSPEC FILE

image

  1. Add In Folder

image

  1. Use in Form
Image.asset(
            "assets/images/login_image.png",
            fit: BoxFit.cover,
          ),

image

Output :

image

Adding Google Fonts

  1. iMPORT dEPENEDENCY FROM PUB.DEV

flutter pub add google_fonts

  1. In Main File Specify Font

image

Use SpaceBox For Adding Space rather than Padding

Adding Text Fields

TextFormField(
            decoration: InputDecoration(
                labelText: "Username", hintText: "Enter Your Username : "),
          ),
          SizedBox(height: 20.0),
          TextFormField(
            decoration: InputDecoration(
                labelText: "Password", hintText: "Enter Your Password : "),
          )
          

image

image

Specify TextField Size

Add Padding(for specifying size in symmetrical order) and add Column (for multiple Children)

 Padding(
            padding:
                const EdgeInsets.symmetric(vertical: 16.0, horizontal: 32.0),
            child: Column(
              children: [
                TextFormField(
                  decoration: InputDecoration(
                      labelText: "Username",
                      hintText: "Enter Your Username : "),
                ),
                SizedBox(height: 20.0),
                TextFormField(
                  decoration: InputDecoration(
                      labelText: "Password",
                      hintText: "Enter Your Password : "),
                )
              ],
            ),
          )

image

Output :

image

Add Button

image

Final Output

image

For easy routing make a class and define instance variable and use them (make them static so we not neet to instantiate again and again)

image

image

image

Changing Size and Adding Naviation to Button

image

Making String Interpolation with 'Welcome Text' :

  1. Change Class From Stateless to stateful widget

image

  1. Create Empty Variable

var name = "";

  1. Make Onchange Method and use setState() method to rendert again and again

image

Making Button Using Container for Adding Animation

Container(
                  
                    width: 150,
                    height: 50,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                        color: Colors.deepPurple,
                        borderRadius: BorderRadius.circular(
                         8,
                        )),
                    child: changeButton
                        ? const Icon(
                            Icons.done,
                            color: Colors.white,
                          )
                        : const Text(
                            "Login",
                            style: TextStyle(
                                fontSize: 18,
                                fontWeight: FontWeight.bold,
                                color: Colors.white),
                          ),
                  ),

Adding Animation to Container

MAKE Container animated and add duration

AnimatedContainer(
                    duration: const Duration(seconds: 1),
                    width: changeButton ? 50 : 150,
                    height: 50,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                        color: Colors.deepPurple,
                        borderRadius: BorderRadius.circular(
                          changeButton ? 50 : 8,
                        )),
                    child: changeButton
                        ? const Icon(
                            Icons.done,
                            color: Colors.white,
                          )
                        : const Text(
                            "Login",
                            style: TextStyle(
                                fontSize: 18,
                                fontWeight: FontWeight.bold,
                                color: Colors.white),
                          ),
                  ),

Add Variable for check

bool changeButton = false;

Wrap under InkWell and Use onTap() and add setState() in that

InkWell(
                  onTap: () async {
                    setState(() {
                      changeButton = true;
                    });
                   
                  },
                  child: AnimatedContainer(
                    duration: const Duration(seconds: 1),
                    width: changeButton ? 50 : 150,
                    height: 50,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                        color: Colors.deepPurple,
                        borderRadius: BorderRadius.circular(
                          changeButton ? 50 : 8,
                        )),
                    child: changeButton
                        ? const Icon(
                            Icons.done,
                            color: Colors.white,
                          )
                        : const Text(
                            "Login",
                            style: TextStyle(
                                fontSize: 18,
                                fontWeight: FontWeight.bold,
                                color: Colors.white),
                          ),
                  ),
                )

as animation will be of one second so after 1 second we have to change screen

Add Navigator

onTap: () async {
                    setState(() {
                      changeButton = true;
                    });
                    await Future.delayed(Duration(seconds: 1));
                    Navigator.pushNamed(context, MyRoute.homeRoute);
                  }
Final Button
InkWell(
                  onTap: () async {
                    setState(() {
                      changeButton = true;
                    });
                    await Future.delayed(Duration(seconds: 1));
                    Navigator.pushNamed(context, MyRoute.homeRoute);
                  },
                  child: AnimatedContainer(
                    duration: const Duration(seconds: 1),
                    width: changeButton ? 50 : 150,
                    height: 50,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                        color: Colors.deepPurple,
                        borderRadius: BorderRadius.circular(
                          changeButton ? 50 : 8,
                        )),
                    child: changeButton
                        ? const Icon(
                            Icons.done,
                            color: Colors.white,
                          )
                        : const Text(
                            "Login",
                            style: TextStyle(
                                fontSize: 18,
                                fontWeight: FontWeight.bold,
                                color: Colors.white),
                          ),
                  ),
                )

Use Ternery Operator

/* color: changeButton ? Colors.deepPurple : Colors.deepOrange ,*/

Added Icon

child: changeButton
                        ? const Icon(
                            Icons.done,
                            color: Colors.white,
                          )
                        : const Text(
                            "Login",
                            style: TextStyle(
                                fontSize: 18,
                                fontWeight: FontWeight.bold,
                                color: Colors.white),
                          ),

Output : image

image

Setting Button to Original State

image

Adding Validation

Wrap Outer Column under Form

image

Make Form Key (_ --> For Private )

final _formKey = GlobalKey<FormState>();

use under Form

key: _formKey,

Move Core in Method

image

Call Function

image

Add Validator Under Text Field

image

Wrap with Method

image

Done

image

Improving HomePage

Make Drawer

Make A Stateless Widget

image

Import in Scaffold

image

Adding Image From Network

  final _imageUrl =
      "https://st3.depositphotos.com/1037987/15097/i/600/depositphotos_150975580-stock-photo-portrait-of-businesswoman-in-office.jpg";

Using Image

currentAccountPicture: Image.network(_imageUrl),

Output

image

Circiling Imaage

use

 currentAccountPicture: CircleAvatar(
                backgroundImage: NetworkImage(_imageUrl),
              ),

Output :

image

Adding Color to Whole Drawer

Wrap ListView with container and set color to deepPurple

image

Adding ListTiles

ListTile(
              leading: Icon(
                CupertinoIcons.profile_circled,
                color: Colors.white,
              ),
              title: Text(
                "Profile",
                textScaleFactor: 1.2,
                style: TextStyle(color: Colors.white),
              ),
            ),

Output

image

Changing HomePage Theme

image

Output :

image

Seperating Theme

image

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

class MyTheme {
  static ThemeData lightTheme(BuildContext context) => ThemeData(
        primarySwatch: Colors.deepPurple,
        fontFamily: GoogleFonts.lato().fontFamily,
        appBarTheme: AppBarTheme(
            color: Colors.white,
            elevation: 0.0,
            iconTheme: IconThemeData(color: Colors.black),
            titleTextStyle: Theme.of(context).textTheme.titleLarge),
      );

  static ThemeData DarkTheme(BuildContext context) =>
      ThemeData(brightness: Brightness.dark);
}

Import Theme

image

Ouput

Same as Above

Add Model For Data

image

class CatelogModel {
  static final Items = [
    Item(
        id: "1",
        name: "iPhone 12 Pro",
        desc: "Apple iPhone 12th generation",
        price: 999,
        color: "#33505a",
        image:
            "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRISJ6msIu4AU9_M9ZnJVQVFmfuhfyJjEtbUm3ZK11_8IV9TV25-1uM5wHjiFNwKy99w0mR5Hk&usqp=CAc")
  ];
}

class Item {
  final String id;
  final String name;
  final String desc;

  final num price;
  final String color;
  final String image;

  Item(
      {required this.id,
      required this.name,
      required this.desc,
      required this.price,
      required this.color,
      required this.image});
}


make item_widget class

image

import 'package:catelog_application/models/catelog.dart';
import 'package:flutter/material.dart';

class ItemWidget extends StatelessWidget {
  final Item item;
  const ItemWidget({super.key, required this.item}) : assert(item != null);

  @override
  Widget build(BuildContext context) {
    return Card(
      // elevation: 0.5,
      child: ListTile(
        leading: Image.network(item.image),
        title: Text(item.name),
        subtitle: Text(item.desc),
        trailing: Text(
          "\$ ${item.price}",
          textScaleFactor: 1.5,
          style: TextStyle(
            color: Colors.deepPurple,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }
}

in HomePage body make

image

Lets Generate DummyList

final dummyList = List.generate(50, (index) => CatelogModel.Items[0]);

Return

image

Output :

image

Adding Data

Make Folder in Assests > Files > iMPORT Data File

{
    "products": [
        {
            "id": 1,
            "name": "iPhone 12 Pro",
            "desc": "Apple iPhone 12th generation",
            "price": 999,
            "color": "#33505a",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRISJ6msIu4AU9_M9ZnJVQVFmfuhfyJjEtbUm3ZK11_8IV9TV25-1uM5wHjiFNwKy99w0mR5Hk&usqp=CAc"
        },
        {
            "id": 2,
            "name": "Pixel 5",
            "desc": "Google Pixel phone 5th generation",
            "price": 699,
            "color": "#00ac51",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSd0JhwLvm_uLDLc-la7hK9WyVpe9naJFcebKfhcICiq2KtvXDePNAU_9QO06LPcQ0K0fLByc7m&usqp=CAc"
        },
        {
            "id": 3,
            "name": "M1 Macbook Air",
            "desc": "Apple Macbook air with apple silicon",
            "price": 1099,
            "color": "#e0bfae",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSMOMstwtmLnjFb3NHiDJ_kcQnueNVH-rv_3ps96HZmXlFumKWaiBqq_L4Uoyx3iFiNTrXNEbyB&usqp=CAc"
        },
        {
            "id": 4,
            "name": "Playstation 5",
            "desc": "Sony Playstation 5th generation",
            "price": 500,
            "color": "#544ee4",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSMOMstwtmLnjFb3NHiDJ_kcQnueNVH-rv_3ps96HZmXlFumKWaiBqq_L4Uoyx3iFiNTrXNEbyB&usqp=CAc"
        },
        {
            "id": 5,
            "name": "Airpods Pro",
            "desc": "Apple Aipods Pro 1st generation",
            "price": 200,
            "color": "#e3e4e9",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQROEs084z65psoo06zYl5R0tUzywOVKVQZzmzqCj3PDP1vVJTWv3gGwGMFENSy4qV4n7sEQjE&usqp=CAc"
        },
        {
            "id": 6,
            "name": "iPad Pro",
            "desc": "Apple iPad Pro 2020 edition",
            "price": 799,
            "color": "#f73984",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSNzUeRQ5uH7E3hpECib8qxdhfHv6SnUGT7mOsew_xiOoqRR7ZpdH-TQ4J6-HuIEfqHimYyPXWH&usqp=CAc"
        },
        {
            "id": 7,
            "name": "Galaxy S21 Ultra",
            "desc": "Samsung Galaxy S21 Ultra 2021 edition",
            "price": 1299,
            "color": "#1c1c1c",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTT_PZcc0wicVYR992s5QCIDLYy8t-z-9kibTUdWZBN2sd86aaqdAJfhvxAwZNWV9wfdzDikpr1&usqp=CAc"
        },
        {
            "id": 8,
            "name": "Galaxy S21",
            "desc": "Samsung Galaxy S21 2021 edition",
            "price": 899,
            "color": "#7c95eb",
            "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRBNHd7FwarbxA1xdMFt24KazjcR4dWPH_t_T5dz4YNK1s7rJAQ8gOIuR_NRw6eeiQgFhbZ9sAN&usqp=CAc"
        }
    ]
}

In homepage Make it Stateful widget by clicking on Bulb Button

Then Import a initState method from overridin file inside _HomePage class (Private) -- to get data before initilization

image

Make LoadFolder method in it and them call it outside

image

You can verify the data by printing it

image

As the Method is Returning String we have to decode it using decoder

import import 'dart:convert';

use

var decodedData = jsonDecode(catelogJson); //String to map
    print(decodedData);
        var productData = decodedData["products"];
    print(productData);

image

Json Mapping

image

Change to List

image

Map

image

Replace

image

Call SetState()

image

Done

Improving Code

image

Added Grid View Rather than ListView

image

Output :

image

Added Final Styles

body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: (CatelogModel.Items != null && CatelogModel.Items.isNotEmpty)
            ? /* ListView.builder(
                itemCount: CatelogModel.Items.length,
                itemBuilder: (context, index) {
                  return ItemWidget(
                    item: CatelogModel.Items[index],
                  );
                }) */
            GridView.builder(
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    mainAxisSpacing: 12,
                    crossAxisSpacing: 12),
                itemBuilder: (context, index) {
                  final item = CatelogModel.Items[index];
                  return Card(
                    clipBehavior: Clip.antiAlias,
                    shape: RoundedRectangleBorder(
                        /* side:
                            BorderSide(color: Color.fromARGB(255, 83, 83, 85)), */
                        borderRadius: BorderRadius.circular(10)),
                    child: GridTile(
                      child: Image.network(item.image),
                      header: Container(
                          child: Text(
                            item.name,
                            style: TextStyle(color: Colors.white),
                          ),
                          padding: EdgeInsets.all(12),
                          decoration: BoxDecoration(color: Colors.deepPurple)),
                      footer: Container(
                          child: Text(
                            item.price.toString(),
                            style: TextStyle(color: Colors.white),
                          ),
                          padding: EdgeInsets.all(12),
                          decoration: BoxDecoration(color: Colors.green[600])),
                    ),
                  );
                },
                itemCount: CatelogModel.Items.length,
              )
            : Center(
                child: CircularProgressIndicator(),
              ),
      ),

Output :

image

Now We will Use Velocity-x for rest

Delete and all Velocity Code

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: MyTheme.creamColor,
      // To Start from Area
      body: SafeArea(
          child: Container(
              // Adding Padding
              padding: Vx.m32,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  MyHeader(),
                  if (CatelogModel.Items != null &&
                      CatelogModel.Items.isNotEmpty)
                    CatelogList().expand()
                  else
                    Center(child: CircularProgressIndicator())
                ],
              ))),
    );
   

Sperating Header Element

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

 @override
 Widget build(BuildContext context) {
   return Column(
     // To Start from Left
     crossAxisAlignment: CrossAxisAlignment.start,
     children: [
       "ProDiscounts.github.io"
           // Text Type
           .text
           // exxtra Large
           .xl4
           // Bold
           .bold
           // Color
           .color(MyTheme.darkBluishColor)
           // to make it a widget
           .make(),
       "Trending Products".text.xl2.make()
     ],
   );
 }
}

For getting Catelog List

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

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        shrinkWrap: true,
        itemCount: CatelogModel.Items.length,
        itemBuilder: (context, index) {
          final catelog = CatelogModel.Items[index];
          return CatelogItem(
            catelog: catelog,
          );
        });
  }
}

class CatelogItem extends StatelessWidget {
  final Item catelog;
  const CatelogItem({super.key, required this.catelog})
      : assert(catelog != null);
  @override
  Widget build(BuildContext context) {
    return VxBox(
      child: Row(
        children: [
          CatelogImage(image: catelog.image),
          Expanded(
              child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              catelog.name.text.lg.color(MyTheme.darkBluishColor).bold.make(),
              catelog.desc.text.sm
                  .textStyle(context.captionStyle)
                  .color(MyTheme.darkBluishColor)
                  .bold
                  .make(),
              10.heightBox,
              ButtonBar(
                alignment: MainAxisAlignment.spaceBetween,
                buttonPadding: Vx.mH8,
                children: [
                  "\$${catelog.price}".text.bold.xl.make(),
                  ElevatedButton(
                      style: ButtonStyle(
                          backgroundColor: MaterialStateProperty.all(
                              MyTheme.darkBluishColor),
                          shape: MaterialStatePropertyAll(StadiumBorder())),
                      onPressed: () {},
                      child: "Buy".text.bold.make())
                ],
              ).pOnly(right: 12)
            ],
          ))
        ],
      ),
    ).white.roundedLg.square(150).make().py16();
  }
}

For Adding Image

class CatelogImage extends StatelessWidget {
  final String image;
  const CatelogImage({super.key, required this.image}) : assert(image != null);
  @override
  Widget build(BuildContext context) {
    return Image.network(
      image,
    ).box.p16.rounded.color(MyTheme.creamColor).make().p16();
  }
}

Complete Class

import 'package:catelog_application/widgets/Themes.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'dart:convert';
import '../models/catelog.dart';
import '../widgets/Drawer.dart';
import '../widgets/item_widget.dart';
import 'package:velocity_x/velocity_x.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final days = 30;

  final name = "Avtar";

  @override
  void initState() {
    super.initState();
    loadData();
  }

  loadData() async {
    await Future.delayed(Duration(seconds: 2));
    final catelogJson =
        await rootBundle.loadString("assets/files/catalog.json");
    final decodedData = jsonDecode(catelogJson); //String to map
    var productData = decodedData["products"];
    CatelogModel.Items =
        List.from(productData).map<Item>((item) => Item.fromMap(item)).toList();
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: MyTheme.creamColor,
      // To Start from Area
      body: SafeArea(
          child: Container(
              // Adding Padding
              padding: Vx.m32,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  MyHeader(),
                  if (CatelogModel.Items != null &&
                      CatelogModel.Items.isNotEmpty)
                    CatelogList().expand()
                  else
                    Center(child: CircularProgressIndicator())
                ],
              ))),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Column(
      // To Start from Left
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        "ProDiscounts.github.io"
            // Text Type
            .text
            // exxtra Large
            .xl4
            // Bold
            .bold
            // Color
            .color(MyTheme.darkBluishColor)
            // to make it a widget
            .make(),
        "Trending Products".text.xl2.make()
      ],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        shrinkWrap: true,
        itemCount: CatelogModel.Items.length,
        itemBuilder: (context, index) {
          final catelog = CatelogModel.Items[index];
          return CatelogItem(
            catelog: catelog,
          );
        });
  }
}

class CatelogItem extends StatelessWidget {
  final Item catelog;
  const CatelogItem({super.key, required this.catelog})
      : assert(catelog != null);
  @override
  Widget build(BuildContext context) {
    return VxBox(
      child: Row(
        children: [
          CatelogImage(image: catelog.image),
          Expanded(
              child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              catelog.name.text.lg.color(MyTheme.darkBluishColor).bold.make(),
              catelog.desc.text.sm
                  .textStyle(context.captionStyle)
                  .color(MyTheme.darkBluishColor)
                  .bold
                  .make(),
              10.heightBox,
              ButtonBar(
                alignment: MainAxisAlignment.spaceBetween,
                buttonPadding: Vx.mH8,
                children: [
                  "\$${catelog.price}".text.bold.xl.make(),
                  ElevatedButton(
                      style: ButtonStyle(
                          backgroundColor: MaterialStateProperty.all(
                              MyTheme.darkBluishColor),
                          shape: MaterialStatePropertyAll(StadiumBorder())),
                      onPressed: () {},
                      child: "Buy".text.bold.make())
                ],
              ).pOnly(right: 12)
            ],
          ))
        ],
      ),
    ).white.roundedLg.square(150).make().py16();
  }
}

class CatelogImage extends StatelessWidget {
  final String image;
  const CatelogImage({super.key, required this.image}) : assert(image != null);
  @override
  Widget build(BuildContext context) {
    return Image.network(
      image,
    ).box.p16.rounded.color(MyTheme.creamColor).make().p16();
  }
}

Ouput :

image

Seperating Files

image

Adding a Route in Cart

class MyRoute {
  static String homeRoute = "/";
  static String homeDetailsRoute = "/details";
  static String loginRoute = "/Login";
  static String cartPage = "/Cart";
}

Creating Cart Page

import 'package:catelog_application/cors/store.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/src/widgets/placeholder.dart';
import 'package:velocity_x/velocity_x.dart';

import '../models/cart.dart';
import '../utils/routes.dart';
import '../widgets/Themes.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: context.canvasColor,
      appBar: AppBar(
        backgroundColor: context.canvasColor,
        iconTheme: IconThemeData(color: context.theme.hintColor),
        title: "Cart".text.bold.color(context.theme.hintColor).make(),
        centerTitle: true,
      ),
      body: Column(
        children: [_CartList().p32().expand(), Divider(), _CartTotal()],
      ),
    );
  }
}

class _CartTotal extends StatelessWidget {
  _CartTotal({super.key});

  @override
  Widget build(BuildContext context) {
    final CartModel _cart = (VxState.store as MyStore).cart;
    return SizedBox(
      height: 200,
      child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
        VxConsumer(
            builder: (context, store, status) {
              return "\$${_cart.totalPrice}"
                  .text
                  .xl5
                  .color(context.theme.hintColor)
                  .make();
            },
            mutations: {RemoveMutation}),
        30.widthBox,
        ElevatedButton(
                onPressed: () {
                  Navigator.pushNamed(context, MyRoute.loginRoute);
                  /* ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: "Shop Not Opened Yet..".text.make())); */
                },
                style: ButtonStyle(
                    backgroundColor:
                        MaterialStatePropertyAll(Colors.deepPurple)),
                child: "Buy Now".text.white.make())
            .w24(context)
            .h10(context)
      ]),
    );
  }
}

class _CartList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    VxState.watch(context, on: [RemoveMutation]);
    final CartModel _cart = (VxState.store as MyStore).cart;
    return _cart.items.isEmpty
        ? "Cart is Empty".text.xl3.makeCentered()
        : ListView.builder(
            itemCount: _cart.items.length,
            itemBuilder: (context, index) => ListTile(
                  leading: Icon(Icons.done, color: context.theme.errorColor),
                  trailing: IconButton(
                    icon: Icon(Icons.remove_circle_outline,
                        color: context.theme.errorColor),
                    onPressed: () => RemoveMutation(_cart.items[index])
                    // _cart.remove();
                    // setState(() {});
                    ,
                  ),
                  title: _cart.items[index].name.text
                      .color(context.theme.hintColor)
                      .make(),
                ));
  }
}

Output

image

Craeting a Mapping Model For Cart

image

Mapping

import 'package:catelog_application/cors/store.dart';
import 'package:catelog_application/models/catelog.dart';
import 'package:velocity_x/velocity_x.dart';

class CartModel {


  late CatelogModel _catelog;

  // catelog Field

// COLLECTION OF IDS - FOR EACT ITEM
  final List<int> _itemIds = [];

  // get Catelog
  CatelogModel get catelog => _catelog;

  // set

  set catelog(CatelogModel newCatelog) {
    assert(newCatelog != null);
    _catelog = newCatelog;
  }

  // Get Items
  List<Item> get items => _itemIds.map((id) => _catelog.getById(id)).toList();

  // get total price
  num get totalPrice =>
      items.fold(0, (total, current) => total + current.price);

  // Add Item

  void add(Item item) {
    _itemIds.add(item.id);
  }

  // remove
  void remove(Item item) {
    _itemIds.remove(item.id);
  }
}

// Add Item
class AddMutation extends VxMutation<MyStore> {
  final Item item;

  AddMutation(this.item);
  @override
  perform() {
    store?.cart._itemIds.add(item.id);
  }
}

// Remove Item
class RemoveMutation extends VxMutation<MyStore> {
  final Item item;

  RemoveMutation(this.item);
  @override
  perform() {
    store?.cart._itemIds.remove(item.id);
  }
}

Seperating Widget

image

Add Seperate Logic

import 'package:catelog_application/cors/store.dart';
import 'package:flutter/material.dart';
import 'package:velocity_x/velocity_x.dart';

import '../../models/cart.dart';
import '../../models/catelog.dart';
import '../Themes.dart';

class AddToCart extends StatelessWidget {
  final Item catelog;
  AddToCart({super.key, required this.catelog});

  // final _cart = CartModel();

  @override
  Widget build(BuildContext context) {
    // VxState.listen(context, to: []);
    VxState.watch(context, on: [AddMutation, RemoveMutation]);

    final CartModel _cart = (VxState.store as MyStore).cart;
    bool isInCart = _cart.items.contains(catelog) ?? false;
    return ElevatedButton(
        style: ButtonStyle(
            backgroundColor: MaterialStateProperty.all(MyTheme.darkBluishColor),
            shape: MaterialStatePropertyAll(StadiumBorder())),
        onPressed: () {
          if (!isInCart) {
            AddMutation(catelog);
            // setState(() {});
          }
        },
        child: isInCart ? Icon(Icons.done) : "Add to Card".text.bold.make());
  }
}

CatelogHeader

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

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

  @override
  Widget build(BuildContext context) {
    return Column(
      // To Start from Left
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        "ProDiscounts.github.io"
            // Text Type
            .text
            // exxtra Large
            .xl4
            // Bold
            .bold
            // Color
            .color(context.theme.hintColor)
            // to make it a widget
            .make()
            .p0(),
        "Trending Products".text.xl2.color(context.theme.errorColor).make(),
      ],
    );
  }
}

CatelogImage

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

import '../Themes.dart';

class CatelogImage extends StatelessWidget {
  final String image;
  const CatelogImage({super.key, required this.image}) : assert(image != null);
  @override
  Widget build(BuildContext context) {
    return Image.network(
      image,
    ).box.p16.rounded.color(MyTheme.creamColor).make().p16();
  }
}

CatelogImage

import 'package:catelog_application/models/cart.dart';
import 'package:catelog_application/pages/Home_Details_Page.dart';
import 'package:flutter/material.dart';
import 'package:velocity_x/velocity_x.dart';

import '../../models/catelog.dart';
import '../Themes.dart';
import 'add_to_cart.dart';
import 'catelog_image.dart';

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

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        shrinkWrap: true,
        itemCount: CatelogModel.Items.length,
        itemBuilder: (context, index) {
          final catelog = CatelogModel.Items[index];
          return InkWell(
            onTap: () => {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => HomeDetailsPage(catelog: catelog),
                ),
              ),
            },
            child: CatelogItem(
              catelog: catelog,
            ),
          );
        });
  }
}

class CatelogItem extends StatelessWidget {
  final Item catelog;
  const CatelogItem({super.key, required this.catelog})
      : assert(catelog != null);
  @override
  Widget build(BuildContext context) {
    return VxBox(
      child: Row(
        children: [
          Hero(
              tag: Key(catelog.id.toString()),
              child: CatelogImage(image: catelog.image)),
          Expanded(
              child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              catelog.name.text.lg.color(MyTheme.darkCreamColor).bold.make(),
              catelog.desc.text.sm
                  .textStyle(context.captionStyle)
                  .color(MyTheme.darkCreamColor)
                  .bold
                  .make(),
              10.heightBox,
              ButtonBar(
                alignment: MainAxisAlignment.spaceBetween,
                buttonPadding: Vx.mH8,
                children: [
                  "\$${catelog.price}".text.bold.xl.make(),
                  AddToCart(
                    catelog: catelog,
                  )
                ],
              ).pOnly(right: 12)
            ],
          ))
        ],
      ),
    ).white.roundedLg.square(150).make().py16();
  }
}

image

image

Adding Themes

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:velocity_x/velocity_x.dart';

class MyTheme {
  static ThemeData lightTheme(BuildContext context) => ThemeData(
        primarySwatch: Colors.deepPurple,
        fontFamily: GoogleFonts.poppins().fontFamily,
        buttonColor: darkBluishColor,
        accentColor: creamColor,
        hintColor: darkBluishColor,
        errorColor: Vx.black,
        appBarTheme: AppBarTheme(
            color: Colors.deepPurple,
            elevation: 0.5,
            iconTheme: IconThemeData(color: Colors.white),
            titleTextStyle: Theme.of(context).textTheme.titleLarge),
      );

  static ThemeData DarkTheme(BuildContext context) => ThemeData(
        primarySwatch: Colors.deepPurple,
        fontFamily: GoogleFonts.poppins().fontFamily,
        canvasColor: darkCreamColor,
        cardColor: Vx.black,
        buttonColor: ExtradarkBluishColor,
        accentColor: creamColor,
        hintColor: creamColor,
        errorColor: creamColor,
        appBarTheme: AppBarTheme(
            color: Colors.deepPurple,
            elevation: 0.5,
            iconTheme: IconThemeData(color: Colors.white),
            titleTextStyle: Theme.of(context).textTheme.titleLarge),
      );

  static Color creamColor = Color(0xfff5f5f5);
  static Color darkCreamColor = Vx.gray900;
  static Color darkBluishColor = Colors.deepPurple;
  static Color ExtradarkBluishColor = Vx.indigo500;
}

Try Changing from Main from Theme.system to light or dark

Getting Data from Http/Network

Add Package http from pub

import Package

import 'package:http/http.dart' as http;

Add Url

image

Update

image

and

image

Done

image

Deployment

Live Deployed Application Catelog Application

Best Video For Firebase Development Deploy On Firebase

Thanks TO @CodePur

and

For Making it Possible For Me 👍

Releases

No releases published

Packages

 
 
 

Contributors