Flutter Pizza App with Razorpay Integration

Last updated Oct 11, 2021


In this Flutter application we will show you a Pizza Application which will get the Data from Firebase and Integrate RazorPay Payment gateway.

What we will learn

  • Create Simple flutter application
  • Integrate Firebase data with flutter
  • Fetch data from Firebase database
  • Integrate Razorpay Payment Gateway

 

Flutter Pizza application

 

Let's get started

Step 1: Create a flutter application in your respected IDE , here i have used Android studio

Step 2: Add required packages in pubspec.yaml file

google_fonts: ^2.1.0
intl: ^0.17.0
url_launcher:
cloud_firestore: ^2.5.3
firebase_core: ^1.7.0
razorpay_flutter: ^1.2.7

 

Step 3: Implement UI

In this application we have two screens

  • List of Pizza's
  • Pizza details with add to cart

 

Let's create List of Pizza screen

SingleChildScrollView(
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text(
        'Hello User',
        style: poppinsTextStyle.copyWith(
          fontSize: 24,
          fontWeight: FontWeight.w500,
          color: blackColor,
        ),
      ),
      Text(
        'Yummy pizza delivered fast & fresh',
        style: poppinsTextStyle.copyWith(
          fontSize: 18,
          fontWeight: FontWeight.w500,
          color: greyColor,
        ),
      ),
      const SizedBox(height: 22),
      Text(
        'Recomended Menu',
        style: poppinsTextStyle.copyWith(
          fontSize: 18,
          fontWeight: FontWeight.w400,
          color: blackColor,
        ),
      ),
      const SizedBox(height: 22),
    
Column(
  // ignore: unnecessary_cast
  children:[]),
      const SizedBox(height: 20),
    ],
  ),
)

 

This will show the Home screen,  at present it can't show any pizza list, because we were not implemented any logic to fetch data from firebase.

 

Design Pizza Details screen

Let' design our details page

import 'package:flutter/material.dart';
import 'package:foodsapp/models/menu.dart';
import 'package:foodsapp/models/size.dart';
import 'package:foodsapp/theme.dart';
import 'package:foodsapp/widgets/size_card.dart';
import 'package:intl/intl.dart';
import 'package:url_launcher/url_launcher.dart';

import 'checkout.dart';

// ignore: must_be_immutable
class DetailScreen extends StatefulWidget {

  Menu menu;

  DetailScreen( this.menu,
      {Key? key})
      : super(key: key);

  @override
  State<DetailScreen> createState() =>
      // ignore: no_logic_in_create_state
      _DetailScreen();
}

class _DetailScreen extends State<DetailScreen> {


  _DetailScreen();

  launchUrl(String url) async {
    launch(url);
  }

  int i = 1;
  int price =0;
  int pricePromo =0;
  int dataPrice =0;
  int dataPricePromo=0 ;



  bool isMini = true;
  bool isSedang = false;
  bool isBesar = false;
  bool isSuperBesar = false;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    price=widget.menu.price;
    dataPrice=widget.menu.price;
    pricePromo=widget.menu.pricePromo;
    dataPricePromo=widget.menu.pricePromo;
  }

  void _minus() {
    setState(() {
      if (i > 1) {
        i--;
        if (isMini == true) {
          price = dataPrice * i;
          pricePromo = dataPricePromo * i;
        } else if (isSedang == true) {
          price = (dataPrice ) * i;
          pricePromo = (dataPricePromo ) * i;
        } else if (isBesar == true) {
          price = (dataPrice ) * i;
          pricePromo = (dataPricePromo ) * i;
        } else if (isSuperBesar == true) {
          price = (dataPrice ) * i;
          pricePromo = (dataPricePromo ) * i;
        }
      }
    });
  }

  void _plus() {
    setState(() {
      i++;

      if (isMini == true) {
        price = dataPrice * i;
        pricePromo = dataPricePromo * i;
      } else if (isSedang == true) {
        price = (dataPrice ) * i;
        pricePromo = (dataPricePromo ) * i;
      } else if (isBesar == true) {
        price = (dataPrice ) * i;
        pricePromo = (dataPricePromo ) * i;
      } else if (isSuperBesar == true) {
        price = (dataPrice ) * i;
        pricePromo = (dataPricePromo ) * i;
      }
    });
  }

  void _clickMini() {
    setState(() {


    });
  }

  void _clickSedang() {
    setState(() {


    });
  }

  void _clickBesar() {
    setState(() {


    });
  }

  void _clickSuperBesar() {
    setState(() {


    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: [
            Image.network(
              widget.menu.image,
              width: MediaQuery.of(context).size.width,
              fit: BoxFit.cover,
            ),

            ListView(
              children: [
                const SizedBox(height: 264),
                Container(
                  width: MediaQuery.of(context).size.width,
                  decoration: const BoxDecoration(
                    borderRadius: BorderRadius.vertical(
                      top: Radius.circular(20),
                    ),
                    color: Colors.white,
                  ),
                  child: Column(
                    children: [
                      Padding(
                        padding: const EdgeInsets.symmetric(
                          vertical: 30,
                          horizontal: 24,
                        ),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Image.asset(
                              'assets/promo.png',
                              width: 60,
                            ),
                            const SizedBox(height: 8),
                            Row(
                              children: [
                                Expanded(
                                  child: Text(
                                    widget.menu.name,
                                    style: poppinsTextStyle.copyWith(
                                      fontSize: 18,
                                      fontWeight: FontWeight.w500,
                                      color: blackColor,
                                    ),
                                  ),
                                ),

                                InkWell(
                                  onTap: _minus,
                                  child: Image.asset(
                                    'assets/minus.png',
                                    width: 34,
                                  ),
                                ),
                                const SizedBox(width: 16),
                                Text(
                                  '$i',
                                  style: poppinsTextStyle.copyWith(
                                    fontSize: 22,
                                    fontWeight: FontWeight.w500,
                                    color: blackColor,
                                  ),
                                ),
                                const SizedBox(width: 16),
                                InkWell(
                                  onTap: _plus,
                                  child: Image.asset(
                                    'assets/plus.png',
                                    width: 34,
                                  ),
                                ),
                              ],
                            ),
                            const SizedBox(height: 12),
                            Row(
                              children: [
                                Text(
                                  NumberFormat.currency(
                                          locale: 'id',
                                          symbol: 'Rs ',
                                          decimalDigits: 0)
                                      .format(price),
                                  style: poppinsTextStyle.copyWith(
                                    fontSize: 14,
                                    fontWeight: FontWeight.w500,
                                    color: greyColor,
                                    decoration: TextDecoration.lineThrough,
                                  ),
                                ),
                                const SizedBox(width: 4),
                                Text(
                                  NumberFormat.currency(
                                          locale: 'id',
                                          symbol: 'Rs ',
                                          decimalDigits: 0)
                                      .format(pricePromo),
                                  style: poppinsTextStyle.copyWith(
                                    fontSize: 14,
                                    fontWeight: FontWeight.w500,
                                    color: yellowColor,
                                  ),
                                ),
                              ],
                            ),
                            const SizedBox(height: 18),
                            Text(
                              'Choose Options',
                              style: poppinsTextStyle.copyWith(
                                fontSize: 14,
                                fontWeight: FontWeight.w500,
                                color: blackColor,
                              ),
                            ),
                            const SizedBox(height: 12),
                            SizedBox(
                              height: 40,
                              child: ListView(
                                scrollDirection: Axis.horizontal,
                                shrinkWrap: true,
                                children: [
                                  InkWell(
                                    onTap: _clickMini,
                                    child: SizeCard(
                                      Size(
                                        id: 1,
                                        name: 'Veg',
                                        isActive: isMini,
                                      ),
                                    ),
                                  ),
                                  const SizedBox(width: 12),
                                  InkWell(
                                    onTap: _clickSedang,
                                    child: SizeCard(
                                      Size(
                                        id: 2,
                                        name: 'Non Veg',
                                        isActive: isSedang,
                                      ),
                                    ),
                                  ),
                                  const SizedBox(width: 12),
                                  InkWell(
                                    onTap: _clickBesar,
                                    child: SizeCard(
                                      Size(
                                        id: 3,
                                        name: 'Side Order',
                                        isActive: isBesar,
                                      ),
                                    ),
                                  ),
                                  const SizedBox(width: 12),
                                  InkWell(
                                    onTap: _clickSuperBesar,
                                    child: SizeCard(
                                      Size(
                                        id: 4,
                                        name: 'Beverages',
                                        isActive: isSuperBesar,
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            const SizedBox(height: 18),
                            Text(
                              'About Product',
                              style: poppinsTextStyle.copyWith(
                                fontSize: 14,
                                fontWeight: FontWeight.w500,
                                color: blackColor,
                              ),
                            ),
                            const SizedBox(height: 12),
                            // ignore: sized_box_for_whitespace
                            Container(
                              width: MediaQuery.of(context).size.width,
                              child: Text(
                                widget.menu.note,
                                style: poppinsTextStyle.copyWith(
                                  fontSize: 14,
                                  fontWeight: FontWeight.w300,
                                  color: greyColor,
                                ),
                              ),
                            ),
                            const SizedBox(height: 18),
                            Text(
                              'Lokasi Burger Jawa',
                              style: poppinsTextStyle.copyWith(
                                fontSize: 14,
                                fontWeight: FontWeight.w500,
                                color: blackColor,
                              ),
                            ),
                            const SizedBox(height: 12),
                            InkWell(
                              onTap: () {
                                launchUrl('https://www.dominos.co.in/?share');
                              },
                              child: Row(
                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                children: [
                                  Image.asset(
                                    'assets/store.png',
                                    width: 50,
                                  ),
                                  const SizedBox(width: 18),
                                  Expanded(
                                    child: Text(
                                          'Domino''s Pizza India, ower-D, Plot No. 5,',
                                      style: poppinsTextStyle.copyWith(
                                        fontSize: 14,
                                        fontWeight: FontWeight.w500,
                                        color: greyColor,
                                      ),
                                    ),
                                  ),
                                  const Spacer(),
                                  IconButton(
                                    onPressed: () {},
                                    icon: Icon(
                                      Icons.chevron_right,
                                      color: greyColor,
                                      size: 30,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            const SizedBox(height: 40),
                            // ignore: sized_box_for_whitespace
                            Container(
                              width: MediaQuery.of(context).size.width,
                              // ignore: deprecated_member_use
                              child: RaisedButton(
                                padding: const EdgeInsets.only(
                                  top: 12,
                                  bottom: 12,
                                ),
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(18),
                                ),
                                elevation: 0,
                                focusElevation: 0,
                                hoverElevation: 0,
                                disabledElevation: 0,
                                highlightElevation: 0,
                                onPressed: () async{

                                  var result=await Navigator.push(context, MaterialPageRoute(builder: (context){
                                    return CheckoutScreen(widget.menu);
                                  }));

                                  print("result $result");

                                  if(result['status']==1||result['status']==2)
                                    {
                                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Order Placed  Success"),))
                                      ;
                                      Navigator.pop(context);
                                    }
                                  else if(result['status']==0)
                                    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Order Placed  failed, please try again"),))
                                  ;
                                },
                                color: yellowColor,
                                child: Text(
                                  'Order',
                                  style: poppinsTextStyle.copyWith(
                                    fontSize: 18,
                                    fontWeight: FontWeight.w500,
                                    color: whiteColor,
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(20),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  InkWell(
                    onTap: () {
                      Navigator.of(context).pop();
                    },
                    child: Image.asset('assets/btn_back.png', width: 40),
                  ),
                  InkWell(
                    onTap: () {},
                    child: Image.asset('assets/btn_share.png', width: 40),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

 

Step 4: Integrate Firebase data with flutter

We are ready with our design part, now we need to create our data on the Firebase database. Read here about Integrate firebase with flutter.

Our database consist of below fields

Flutter Firebase integration

 

 

Step 5: Fetch data from Firebase

Now we are ready with UI and Pizza database, let's add functionality to fetch live data from firebase data. To fetch data from firebase we are using the streambuilder widget

First we need to create instance of FirebaseFirestore and CollectionReference respectively

 

FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference products = firestore.collection('products');

 

 

StreamBuilder<QuerySnapshot>(
    stream: products.orderBy('id', descending: false).snapshots(),
    builder: (_, snapshot) {
      if (snapshot.hasData) {
        return Column(
          // ignore: unnecessary_cast
          children: (snapshot.data! as QuerySnapshot)
              .docs
              .map(
                (e) => MenuCard(
                  Menu(
                    id: e['id'],
                    image: e['image'],
                    name: e['name'],
                    price: e['price'],
                    pricePromo: e['pricePromo'],
                    note: e['note'],
                    isPromo: e['isPromo'],
                  ),
                ),
              )
              .toList(),
        );
      } else {
        return const Center(
          child: CircularProgressIndicator(),
        );
      }
    })

 

Step 6: Integrate RazoPay

To integrate razorpay in flutter application we need to create an application Razorpay dashboard. Read here Integrate Razorpay Payment Gateway with flutter

Our Payment class will be like this

import 'package:flutter/material.dart';
import 'package:foodsapp/models/menu.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
class CheckoutScreen extends StatefulWidget{
  Menu menu;
  CheckoutScreen(this. menu);

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return CheckoutScreenState();
  }

}

class CheckoutScreenState extends State<CheckoutScreen> {
  late Razorpay _razorpay;
  String PAYMENT_STATUS="";
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _razorpay = Razorpay();
    _razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
    _razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
    _razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
    createOrder();
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Payment',
      theme: ThemeData(

        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text("Checkout Process"),),
        body: Container(
          width: double.infinity,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [

           
              SizedBox(height: 20,),
              Text(PAYMENT_STATUS,style: TextStyle(color: Colors.brown,fontWeight: FontWeight.bold,fontSize: 22,),textAlign: TextAlign.center,),
            ],
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _razorpay.clear();

  }
  void _handlePaymentSuccess(PaymentSuccessResponse response) {
    print("Payment Process On response success ${response.paymentId}");
    setState(() {
      PAYMENT_STATUS="Payment Success.\n\nYour Payment Id is: ${response.paymentId}";
    });
    Map<String,dynamic>payment=Map();
    payment['status']=1;
    payment['order_id']=response.orderId;
    payment['payment_id']=response.paymentId;

    Navigator.pop(context,payment);
  }

  void _handlePaymentError(PaymentFailureResponse response) {

    print("Payment Process On response Error ${response.message}");
    setState(() {
      PAYMENT_STATUS="Payment Failed.  ${response.message}";
    });
    Map<String,dynamic>payment=Map();
    payment['status']=0;


    Navigator.pop(context,payment);
  }

  void _handleExternalWallet(ExternalWalletResponse response) {
    print("Payment Process On response Waller ${response.walletName}");
    setState(() {
      PAYMENT_STATUS="Payment Done with wallet information .  ${response.walletName}";
    });
    Map<String,dynamic>payment=Map();
    payment['status']=2;
    Navigator.pop(context,payment);
  }


  void createOrder() async
  {
    var options = {
      'key': 'PUT_API_KEY',
      'amount': widget.menu.price*100,
      'name': widget.menu.name,
      'description': widget.menu.note,
      'prefill': {'contact': '9879879879', 'email': 'test_987@razorpay.com'},
      'external': {
        'wallets': ['paytm']
      }
    };

    try {
      _razorpay.open(options);
    } catch (e) {
      debugPrint('Error: e');
    }
  }


}

 

Let's run your application

Flutter Application with Firebase database

 

Flutter Razorpay payment gateway

 

Conclusion: In this flutter application we learned how to integrate firebase with flutter application, fetch data from firestore collections, and integrate Razorpay payment gateway.

 


Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

186 Views

Subscribe For Daily Updates

Flutter Questions
Android Questions