Popular Searches
Popular Course Categories
Popular Courses

Build a Flutter Food Delivery App

Build a Flutter Food Delivery App

Flutter Practical Projects

Build a Flutter Food Delivery App

Building a Flutter Food Delivery App is a practical project that combines Flutter UI development, navigation, state management, reusable widgets, authentication, cloud database integration, cart functionality, order management, and responsive application design. In this project, we will create a food delivery application where users can browse restaurants and food items, view product details, add food to a cart, manage quantities, place orders, and view their order history.

This project is designed to demonstrate how individual Flutter concepts work together to create a complete real-world application.


1. Project Objectives

The main objective of this project is to build a practical food delivery application using Flutter and Dart.

  • Create a modern food delivery user interface.
  • Create reusable Flutter widgets.
  • Implement bottom navigation.
  • Display restaurants and food categories.
  • Display food items dynamically.
  • Create food detail screens.
  • Implement add-to-cart functionality.
  • Manage cart item quantities.
  • Calculate subtotal, delivery fee, and total amount.
  • Implement user authentication.
  • Store food and restaurant information in Firestore.
  • Store customer orders in Firestore.
  • Display order history.
  • Create a complete food ordering workflow.
  • Prepare the application for production deployment.

2. What We Will Build

The application will contain multiple screens connected through navigation.

ScreenPurpose
Splash ScreenDisplays application branding while the application starts.
Login ScreenAllows existing users to sign in.
Registration ScreenAllows new users to create an account.
Home ScreenDisplays categories, restaurants, and recommended food.
Restaurant ScreenDisplays food items belonging to a restaurant.
Food Detail ScreenDisplays detailed information about a food item.
Cart ScreenDisplays selected food items and pricing.
Checkout ScreenAllows users to confirm delivery and payment information.
Order Success ScreenConfirms that the order has been placed.
Orders ScreenDisplays previous and current orders.
Profile ScreenDisplays user information and account options.

3. Technologies Used

TechnologyPurpose
FlutterBuilds the cross-platform application.
DartProgramming language used by Flutter.
Firebase AuthenticationHandles user registration and login.
Cloud FirestoreStores restaurants, food items, users, and orders.
Firebase StorageCan be used for food and restaurant images.
Provider / Riverpod / BlocCan be used for application state management.
Material DesignProvides Flutter UI components and design patterns.

4. Prerequisites

Before starting this project, you should understand basic Flutter and Dart concepts.

  • Dart variables and data types.
  • Functions.
  • Classes and objects.
  • Constructors.
  • Inheritance and polymorphism.
  • Lists and maps.
  • Flutter widgets.
  • StatelessWidget and StatefulWidget.
  • Layouts using Row, Column, Stack, and Container.
  • ListView and GridView.
  • Navigation.
  • Basic asynchronous programming.
  • Basic Firebase concepts.

5. Create the Flutter Project

Create a new Flutter project using the Flutter CLI.

flutter create food_delivery_app

Move into the project directory:

cd food_delivery_app

Run the project:

flutter run

6. Recommended Project Structure

A proper project structure makes a large Flutter application easier to maintain.

lib/
├── main.dart
├── app.dart
├── models/
│   ├── food_model.dart
│   ├── restaurant_model.dart
│   ├── cart_item_model.dart
│   └── order_model.dart
├── screens/
│   ├── splash_screen.dart
│   ├── login_screen.dart
│   ├── register_screen.dart
│   ├── home_screen.dart
│   ├── restaurant_screen.dart
│   ├── food_detail_screen.dart
│   ├── cart_screen.dart
│   ├── checkout_screen.dart
│   ├── orders_screen.dart
│   └── profile_screen.dart
├── widgets/
│   ├── food_card.dart
│   ├── restaurant_card.dart
│   ├── category_item.dart
│   ├── cart_item.dart
│   └── custom_button.dart
├── services/
│   ├── auth_service.dart
│   ├── firestore_service.dart
│   └── order_service.dart
├── providers/
│   ├── cart_provider.dart
│   └── user_provider.dart
└── utils/
    ├── app_colors.dart
    ├── app_constants.dart
    └── validators.dart

7. Application Flow

The overall application flow can be represented as follows:

Application Start
       |
       v
   Splash Screen
       |
       v
Check Authentication
   /           \
Logged In     Logged Out
   |              |
   v              v
Home Screen    Login Screen
   |              |
   |              v
   |          Registration
   |              |
   +--------------+
          |
          v
      Home Screen
          |
          v
Select Restaurant
          |
          v
Select Food
          |
          v
Food Details
          |
          v
Add To Cart
          |
          v
Cart
          |
          v
Checkout
          |
          v
Place Order
          |
          v
Order Confirmation
          |
          v
Order History

8. Create the Main Entry Point

The main.dart file is the entry point of the Flutter application.

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

void main() {
  runApp(const FoodDeliveryApp());
}

9. Create the Main Application

The main application widget defines the overall application configuration.

import 'package:flutter/material.dart';
import 'screens/splash_screen.dart';

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Food Delivery App',
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: const SplashScreen(),
    );
  }
}

10. Create Application Constants

Application constants help avoid repeating the same values throughout the project.

class AppConstants {
  static const String appName = 'Food Delivery';
  static const double deliveryFee = 40.0;
  static const double taxRate = 0.05;
}

11. Create Food Model

A model represents the structure of food data.

class Food {
  final String id;
  final String name;
  final String description;
  final double price;
  final String imageUrl;
  final String category;
  final String restaurantId;
  final bool isAvailable;

  Food({
    required this.id,
    required this.name,
    required this.description,
    required this.price,
    required this.imageUrl,
    required this.category,
    required this.restaurantId,
    required this.isAvailable,
  });
}

12. Create Restaurant Model

class Restaurant {
  final String id;
  final String name;
  final String imageUrl;
  final String description;
  final double rating;
  final String deliveryTime;

  Restaurant({
    required this.id,
    required this.name,
    required this.imageUrl,
    required this.description,
    required this.rating,
    required this.deliveryTime,
  });
}

13. Create Cart Item Model

A cart item contains food information and the quantity selected by the customer.

class CartItem {
  final Food food;
  int quantity;

  CartItem({
    required this.food,
    this.quantity = 1,
  });

  double get totalPrice => food.price * quantity;
}

14. Create Order Model

class OrderModel {
  final String id;
  final String userId;
  final List<CartItem> items;
  final double totalAmount;
  final String address;
  final String status;
  final DateTime createdAt;

  OrderModel({
    required this.id,
    required this.userId,
    required this.items,
    required this.totalAmount,
    required this.address,
    required this.status,
    required this.createdAt,
  });
}

15. Create the Splash Screen

The splash screen introduces the application before navigating to the appropriate screen.

import 'package:flutter/material.dart';
import 'home_screen.dart';
import 'login_screen.dart';

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

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();

    Future.delayed(const Duration(seconds: 2), () {
      if (!mounted) return;

      Navigator.pushReplacement(
        context,
        MaterialPageRoute(
          builder: (_) => const LoginScreen(),
        ),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(
        child: Text(
          'Food Delivery',
          style: TextStyle(
            fontSize: 32,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }
}

16. Design the Login Screen

The login screen allows existing customers to access their accounts.

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

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final emailController = TextEditingController();
  final passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Login'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            TextField(
              controller: emailController,
              decoration: const InputDecoration(
                labelText: 'Email',
              ),
            ),
            const SizedBox(height: 16),
            TextField(
              controller: passwordController,
              obscureText: true,
              decoration: const InputDecoration(
                labelText: 'Password',
              ),
            ),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: () {},
              child: const Text('Login'),
            ),
          ],
        ),
      ),
    );
  }
}

17. Registration Screen

The registration screen collects the customer's basic account information.

  • Name
  • Email
  • Password
  • Phone number
  • Delivery address

18. Home Screen

The home screen is the primary discovery screen of the application. It should provide quick access to categories, restaurants, popular foods, and search functionality.

A typical home screen can contain:

  • Location selector.
  • Search field.
  • Food categories.
  • Promotional banner.
  • Popular restaurants.
  • Recommended food.
  • Bottom navigation.

19. Search Bar

The search bar allows customers to find restaurants or food items quickly.

TextField(
  decoration: InputDecoration(
    hintText: 'Search food or restaurants',
    prefixIcon: const Icon(Icons.search),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
  ),
)

20. Food Categories

Food categories make discovery easier.

CategoryExample Foods
PizzaMargherita, Farmhouse, Paneer Pizza
BurgerVeg Burger, Cheese Burger
IndianPaneer, Biryani, Thali
ChineseNoodles, Fried Rice, Manchurian
DessertsCake, Ice Cream, Brownie
DrinksJuice, Coffee, Shake

21. Category Widget

class CategoryItem extends StatelessWidget {
  final String title;
  final IconData icon;

  const CategoryItem({
    super.key,
    required this.title,
    required this.icon,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        CircleAvatar(
          radius: 28,
          child: Icon(icon),
        ),
        const SizedBox(height: 6),
        Text(title),
      ],
    );
  }
}

22. Restaurant Card

A reusable restaurant card displays important restaurant information.

class RestaurantCard extends StatelessWidget {
  final Restaurant restaurant;

  const RestaurantCard({
    super.key,
    required this.restaurant,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Image.network(
            restaurant.imageUrl,
            height: 160,
            width: double.infinity,
            fit: BoxFit.cover,
          ),
          Padding(
            padding: const EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  restaurant.name,
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text('Rating: ${restaurant.rating}'),
                Text(restaurant.deliveryTime),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

23. Food Card

The food card is one of the most frequently reused widgets in the application.

class FoodCard extends StatelessWidget {
  final Food food;
  final VoidCallback onTap;

  const FoodCard({
    super.key,
    required this.food,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: InkWell(
        onTap: onTap,
        child: Padding(
          padding: const EdgeInsets.all(12),
          child: Row(
            children: [
              ClipRRect(
                borderRadius: BorderRadius.circular(12),
                child: Image.network(
                  food.imageUrl,
                  width: 100,
                  height: 100,
                  fit: BoxFit.cover,
                ),
              ),
              const SizedBox(width: 12),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      food.name,
                      style: const TextStyle(
                        fontSize: 17,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    Text(food.description),
                    const SizedBox(height: 6),
                    Text(
                      '₹${food.price.toStringAsFixed(2)}',
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

24. Restaurant Details Screen

When the user selects a restaurant, the application should display restaurant information and available food items.

  • Restaurant image.
  • Restaurant name.
  • Rating.
  • Delivery time.
  • Restaurant description.
  • Food categories.
  • Food list.

25. Food Detail Screen

The food detail screen displays complete information about a selected food item.

class FoodDetailScreen extends StatelessWidget {
  final Food food;

  const FoodDetailScreen({
    super.key,
    required this.food,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(food.name),
      ),
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Image.network(
              food.imageUrl,
              height: 260,
              width: double.infinity,
              fit: BoxFit.cover,
            ),
            Padding(
              padding: const EdgeInsets.all(20),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    food.name,
                    style: const TextStyle(
                      fontSize: 26,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 10),
                  Text(food.description),
                  const SizedBox(height: 16),
                  Text(
                    '₹${food.price.toStringAsFixed(2)}',
                    style: const TextStyle(
                      fontSize: 22,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

26. Add to Cart

The Add to Cart operation is a core feature of the food delivery application.

When a customer taps the Add to Cart button, the selected food item should be added to the cart. If the same food item already exists in the cart, its quantity should normally increase rather than creating an unnecessary duplicate item.

27. Cart State Management

The cart is shared across multiple screens, so a state management solution is useful.

Possible approaches include:

  • Provider
  • Riverpod
  • Bloc
  • ChangeNotifier
  • ValueNotifier for smaller applications

28. Simple Cart Provider

import 'package:flutter/foundation.dart';

class CartProvider extends ChangeNotifier {
  final List<CartItem> _items = [];

  List<CartItem> get items => _items;

  void addItem(Food food) {
    final index = _items.indexWhere(
      (item) => item.food.id == food.id,
    );

    if (index >= 0) {
      _items[index].quantity++;
    } else {
      _items.add(CartItem(food: food));
    }

    notifyListeners();
  }

  void removeItem(Food food) {
    _items.removeWhere(
      (item) => item.food.id == food.id,
    );

    notifyListeners();
  }

  void increaseQuantity(Food food) {
    final item = _items.firstWhere(
      (item) => item.food.id == food.id,
    );

    item.quantity++;
    notifyListeners();
  }

  void decreaseQuantity(Food food) {
    final item = _items.firstWhere(
      (item) => item.food.id == food.id,
    );

    if (item.quantity > 1) {
      item.quantity--;
    } else {
      _items.remove(item);
    }

    notifyListeners();
  }

  double get subtotal {
    return _items.fold(
      0,
      (sum, item) => sum + item.totalPrice,
    );
  }

  void clearCart() {
    _items.clear();
    notifyListeners();
  }
}

29. Cart Screen

The cart screen should clearly show every selected item.

InformationExample
Food NamePaneer Pizza
Unit Price₹299
Quantity2
Item Total₹598

30. Quantity Controls

Each cart item should provide controls to increase or decrease the quantity.

Row(
  children: [
    IconButton(
      onPressed: () {},
      icon: const Icon(Icons.remove),
    ),
    const Text('1'),
    IconButton(
      onPressed: () {},
      icon: const Icon(Icons.add),
    ),
  ],
)

31. Price Calculation

The checkout amount can be calculated using the following formula:

Subtotal = Sum of all item totals

Tax = Subtotal × Tax Rate

Total = Subtotal + Tax + Delivery Fee

Example:

ItemAmount
Food Items₹700
Delivery Fee₹40
Tax₹35
Total₹775

32. Checkout Screen

The checkout screen is responsible for collecting final order information before the order is submitted.

  • Delivery address.
  • Contact number.
  • Order summary.
  • Subtotal.
  • Delivery fee.
  • Tax.
  • Total amount.
  • Payment method.
  • Place Order button.

33. Address Management

A real-world food delivery application should allow customers to manage delivery addresses.

  • Home address.
  • Work address.
  • Other address.
  • Default address.

34. Payment Method UI

For a learning project, payment methods can initially be represented as UI options.

RadioListTile<String>(
  value: 'Cash',
  groupValue: selectedPayment,
  onChanged: (value) {
    setState(() {
      selectedPayment = value!;
    });
  },
  title: const Text('Cash on Delivery'),
)

For real online payments, a secure payment gateway should be integrated through its official Flutter SDK or backend-supported payment flow.

35. Place Order

When the customer taps Place Order, the application should validate all required information before creating the order.

if (cartItems.isEmpty) {
  return;
}

if (addressController.text.trim().isEmpty) {
  return;
}

// Create order
// Save order to Firestore
// Clear cart
// Navigate to success screen

36. Order Success Screen

After successful order creation, display a confirmation message.

Scaffold(
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Icon(
          Icons.check_circle,
          size: 80,
        ),
        const SizedBox(height: 20),
        const Text(
          'Order Placed Successfully!',
          style: TextStyle(
            fontSize: 24,
            fontWeight: FontWeight.bold,
          ),
        ),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: () {},
          child: const Text('View Orders'),
        ),
      ],
    ),
  ),
)

37. Order Status

Each order can have a status representing its current stage.

StatusMeaning
PendingOrder has been submitted and is awaiting confirmation.
ConfirmedRestaurant has accepted the order.
PreparingFood is being prepared.
ReadyFood is ready for pickup or delivery.
Out for DeliveryDelivery partner is taking the order to the customer.
DeliveredOrder has been delivered.
CancelledOrder has been cancelled.

38. Order Tracking Flow

Order Placed
     |
     v
Pending
     |
     v
Confirmed
     |
     v
Preparing
     |
     v
Ready
     |
     v
Out for Delivery
     |
     v
Delivered

39. Bottom Navigation

Bottom navigation provides quick access to the main sections of the application.

TabPurpose
HomeBrowse food and restaurants.
SearchSearch for food and restaurants.
CartManage selected items.
OrdersView current and previous orders.
ProfileManage account settings.

40. Bottom Navigation Example

BottomNavigationBar(
  currentIndex: currentIndex,
  onTap: (index) {
    setState(() {
      currentIndex = index;
    });
  },
  items: const [
    BottomNavigationBarItem(
      icon: Icon(Icons.home),
      label: 'Home',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.search),
      label: 'Search',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.shopping_cart),
      label: 'Cart',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.receipt_long),
      label: 'Orders',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.person),
      label: 'Profile',
    ),
  ],
)

41. Navigation Between Screens

Flutter provides Navigator APIs for moving between screens.

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => const CartScreen(),
  ),
);

To return to the previous screen:

Navigator.pop(context);

42. Named Routes

For larger applications, named routes can make navigation easier to organize.

MaterialApp(
  routes: {
    '/': (context) => const SplashScreen(),
    '/login': (context) => const LoginScreen(),
    '/home': (context) => const HomeScreen(),
    '/cart': (context) => const CartScreen(),
    '/orders': (context) => const OrdersScreen(),
  },
)

43. Firebase Integration

Firebase can provide backend services without requiring developers to build a complete custom backend from scratch.

For this project, Firebase can be used for:

  • Authentication.
  • Cloud Firestore.
  • Firebase Storage.
  • Analytics.
  • Cloud Messaging.

44. Configure Firebase

Create a Firebase project and connect the Flutter application to it using the official Firebase Flutter configuration process.

The Firebase configuration should be kept separate from application UI code.

45. Firebase Authentication

Firebase Authentication can be used to manage customer accounts.

Typical authentication flow:

User Registration
      |
      v
Firebase Authentication
      |
      v
User Account Created
      |
      v
User Login
      |
      v
Authenticated User
      |
      v
Food Delivery Home Screen

46. Authentication Service

import 'package:firebase_auth/firebase_auth.dart';

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  Future<UserCredential> register(
    String email,
    String password,
  ) {
    return _auth.createUserWithEmailAndPassword(
      email: email,
      password: password,
    );
  }

  Future<UserCredential> login(
    String email,
    String password,
  ) {
    return _auth.signInWithEmailAndPassword(
      email: email,
      password: password,
    );
  }

  Future<void> logout() {
    return _auth.signOut();
  }
}

47. User Profile Data

Authentication manages account credentials, while additional profile information can be stored in Firestore.

Example profile data:

{
  "name": "Customer Name",
  "email": "[email protected]",
  "phone": "9999999999",
  "address": "Customer Address",
  "createdAt": "timestamp"
}

48. Firestore Database Structure

A possible Firestore structure for this application is:

users/
    userId/
        name
        email
        phone
        address

restaurants/
    restaurantId/
        name
        description
        imageUrl
        rating
        deliveryTime

foods/
    foodId/
        name
        description
        price
        imageUrl
        category
        restaurantId
        isAvailable

orders/
    orderId/
        userId
        items
        totalAmount
        address
        paymentMethod
        status
        createdAt

49. Add Food to Firestore

await FirebaseFirestore.instance
    .collection('foods')
    .add({
  'name': 'Paneer Pizza',
  'description': 'Delicious paneer pizza',
  'price': 299,
  'category': 'Pizza',
  'restaurantId': 'restaurant_001',
  'imageUrl': 'IMAGE_URL',
  'isAvailable': true,
});

50. Read Food Data from Firestore

final snapshot = await FirebaseFirestore.instance
    .collection('foods')
    .get();

for (final document in snapshot.docs) {
  print(document.data());
}

51. Display Firestore Data with StreamBuilder

StreamBuilder is useful when the UI should automatically respond to real-time Firestore changes.

StreamBuilder(
  stream: FirebaseFirestore.instance
      .collection('foods')
      .snapshots(),
  builder: (context, snapshot) {
    if (snapshot.connectionState ==
        ConnectionState.waiting) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    if (!snapshot.hasData) {
      return const Center(
        child: Text('No food available'),
      );
    }

    final foods = snapshot.data!.docs;

    return ListView.builder(
      itemCount: foods.length,
      itemBuilder: (context, index) {
        final food = foods[index];

        return ListTile(
          title: Text(food['name']),
          subtitle: Text(
            '₹${food['price']}',
          ),
        );
      },
    );
  },
)

52. Store an Order in Firestore

await FirebaseFirestore.instance
    .collection('orders')
    .add({
  'userId': currentUserId,
  'items': cartItems.map((item) {
    return {
      'foodId': item.food.id,
      'name': item.food.name,
      'price': item.food.price,
      'quantity': item.quantity,
    };
  }).toList(),
  'totalAmount': totalAmount,
  'address': address,
  'paymentMethod': paymentMethod,
  'status': 'Pending',
  'createdAt': FieldValue.serverTimestamp(),
});

53. Read User Orders

final orders = FirebaseFirestore.instance
    .collection('orders')
    .where(
      'userId',
      isEqualTo: currentUserId,
    )
    .snapshots();

54. Order History Screen

The order history screen should show:

  • Order ID.
  • Order date.
  • Food items.
  • Total amount.
  • Order status.
  • Delivery address.

55. Search and Filtering

Food delivery applications contain large amounts of food and restaurant data. Search and filtering improve the customer experience.

Useful filters include:

  • Food category.
  • Price range.
  • Restaurant rating.
  • Vegetarian or non-vegetarian.
  • Delivery time.
  • Popular items.

56. Local Search Filtering

final filteredFoods = foods.where((food) {
  return food.name
      .toLowerCase()
      .contains(searchText.toLowerCase());
}).toList();

57. Favorites Feature

Customers can save frequently ordered foods or restaurants as favorites.

Set<String> favoriteFoodIds = {};

void toggleFavorite(String foodId) {
  if (favoriteFoodIds.contains(foodId)) {
    favoriteFoodIds.remove(foodId);
  } else {
    favoriteFoodIds.add(foodId);
  }
}

58. Ratings and Reviews

A production-level application can allow customers to rate restaurants and food items.

FieldExample
userIduser_123
restaurantIdrestaurant_001
rating5
reviewGreat food and fast delivery.
createdAtFirestore Timestamp

59. Delivery Address Validation

Before placing an order, validate that the delivery address is available and complete.

if (addressController.text.trim().length < 10) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(
      content: Text('Please enter a valid address'),
    ),
  );
  return;
}

60. Form Validation

Forms should validate user input before submitting data.

  • Email should have a valid format.
  • Password should meet minimum requirements.
  • Phone number should contain valid digits.
  • Address should not be empty.
  • Required checkout fields should be completed.

61. Loading States

Network operations may take time. Always provide visual feedback while data is loading.

if (isLoading) {
  return const Center(
    child: CircularProgressIndicator(),
  );
}

62. Error Handling

Applications should handle Firebase and network errors gracefully.

try {
  await authService.login(
    email,
    password,
  );
} on FirebaseAuthException catch (e) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text(
        e.message ?? 'Login failed',
      ),
    ),
  );
}

63. Empty States

Every list should consider the possibility that no data is available.

if (items.isEmpty) {
  return const Center(
    child: Text(
      'No items available',
    ),
  );
}

64. Responsive Design

The application should adapt to different screen sizes.

Flutter provides several useful tools for responsive layouts:

  • MediaQuery.
  • LayoutBuilder.
  • Expanded.
  • Flexible.
  • FractionallySizedBox.
  • OrientationBuilder.

65. Responsive Food Grid

final width = MediaQuery.of(context).size.width;

int columns;

if (width > 1200) {
  columns = 4;
} else if (width > 700) {
  columns = 3;
} else {
  columns = 2;
}

GridView.builder(
  gridDelegate:
      SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: columns,
    childAspectRatio: 0.8,
  ),
  itemBuilder: (context, index) {
    return FoodCard(
      food: foods[index],
      onTap: () {},
    );
  },
)

66. Network Images

Food delivery applications commonly display remote images for restaurants and food items.

Image.network(
  food.imageUrl,
  fit: BoxFit.cover,
  errorBuilder: (
    context,
    error,
    stackTrace,
  ) {
    return const Icon(
      Icons.image_not_supported,
    );
  },
)

67. Image Caching

For production applications with many remote images, image caching can improve scrolling performance and reduce repeated downloads.

68. Food Delivery App UI Components

ComponentFlutter Widget Examples
SearchTextField
CategoryContainer, CircleAvatar
RestaurantCard, ListView
Food GridGridView
CartListView, Card
CheckoutForm, TextFormField
Payment SelectionRadioListTile
NavigationNavigationBar / BottomNavigationBar
DialogsshowDialog
NotificationsSnackBar

69. Recommended Color Structure

A food delivery application generally benefits from a consistent visual system.

class AppColors {
  static const primary = Color(0xFFFF6B35);
  static const background = Color(0xFFF8F8F8);
  static const textPrimary = Color(0xFF222222);
  static const textSecondary = Color(0xFF777777);
  static const success = Color(0xFF2E7D32);
}

70. Theme Configuration

ThemeData(
  useMaterial3: true,
  colorSchemeSeed: Colors.deepOrange,
  scaffoldBackgroundColor: Colors.white,
  appBarTheme: const AppBarTheme(
    centerTitle: true,
  ),
)

71. Admin Side Features

A complete food delivery platform may also contain an admin interface.

  • Add restaurants.
  • Edit restaurants.
  • Delete restaurants.
  • Add food items.
  • Edit food items.
  • Disable unavailable food.
  • View customer orders.
  • Update order status.
  • Manage categories.
  • View basic sales information.

72. Admin Order Workflow

Customer Places Order
        |
        v
Order Saved to Firestore
        |
        v
Admin / Restaurant Dashboard
        |
        v
Confirm Order
        |
        v
Update Status
        |
        v
Customer Receives Updated Status
        |
        v
Order Delivered

73. Firebase Security Rules

Firestore security rules are important because client applications should not have unrestricted access to database data.

A conceptual rule structure may restrict users to their own order records and allow authorized administrative operations separately.

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {

    match /users/{userId} {
      allow read, write:
        if request.auth != null
        && request.auth.uid == userId;
    }

    match /orders/{orderId} {
      allow read, create:
        if request.auth != null;

      allow update:
        if request.auth != null;
    }
  }
}

Production security rules should be carefully designed according to the application's actual authorization model.

74. Real-Time Order Status

Firestore streams can allow the customer interface to react when an order status changes.

FirebaseFirestore.instance
    .collection('orders')
    .doc(orderId)
    .snapshots()

For example:

Restaurant updates:
Pending → Preparing

Customer screen:
Automatically displays:
"Your food is being prepared."

75. Push Notifications

Firebase Cloud Messaging can be considered for notifications such as:

  • Order confirmed.
  • Food preparation started.
  • Order ready.
  • Order out for delivery.
  • Order delivered.
  • Promotional notifications.

76. Cart Validation Before Checkout

Before placing an order, verify that:

  • The cart is not empty.
  • All food items are still available.
  • Prices are current.
  • Delivery address is valid.
  • The user is authenticated.
  • The final amount is calculated again.

77. Preventing Duplicate Orders

Order creation should be designed carefully so that repeated taps or network retries do not unintentionally create duplicate orders.

A production application can use an order state, unique request identifier, or backend-controlled transaction strategy to make order creation safer.

78. Order Summary Widget

Column(
  children: [
    Row(
      mainAxisAlignment:
          MainAxisAlignment.spaceBetween,
      children: [
        const Text('Subtotal'),
        Text('₹700'),
      ],
    ),
    const SizedBox(height: 8),
    Row(
      mainAxisAlignment:
          MainAxisAlignment.spaceBetween,
      children: [
        const Text('Delivery Fee'),
        Text('₹40'),
      ],
    ),
    const Divider(),
    Row(
      mainAxisAlignment:
          MainAxisAlignment.spaceBetween,
      children: [
        const Text(
          'Total',
          style: TextStyle(
            fontWeight: FontWeight.bold,
          ),
        ),
        Text(
          '₹740',
          style: const TextStyle(
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    ),
  ],
)

79. Profile Screen

The profile screen can contain:

  • User name.
  • Email address.
  • Phone number.
  • Saved addresses.
  • Favorite restaurants.
  • Favorite foods.
  • Order history.
  • Help and support.
  • Logout.

80. Logout Functionality

await FirebaseAuth.instance.signOut();

if (!context.mounted) return;

Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(
    builder: (_) => const LoginScreen(),
  ),
  (route) => false,
);

81. Complete User Journey

Open Application
      |
      v
Splash Screen
      |
      v
Login / Register
      |
      v
Home
      |
      +----> Search Food
      |
      +----> Browse Categories
      |
      +----> Browse Restaurants
      |
      v
Food Details
      |
      v
Add To Cart
      |
      v
Cart
      |
      v
Checkout
      |
      v
Select Address
      |
      v
Select Payment
      |
      v
Place Order
      |
      v
Order Created
      |
      v
Order Tracking
      |
      v
Delivered
      |
      v
Order History

82. Complete Application Architecture

UI Layer
   |
   +-- Screens
   +-- Widgets
   |
   v
State Management
   |
   +-- Cart State
   +-- User State
   +-- Order State
   |
   v
Service Layer
   |
   +-- Authentication Service
   +-- Firestore Service
   +-- Order Service
   |
   v
Firebase
   |
   +-- Authentication
   +-- Firestore
   +-- Storage
   +-- Messaging

83. Error Scenarios to Handle

ScenarioExpected Handling
No InternetShow a useful network error message.
Login FailedShow authentication error.
Empty CartPrevent checkout.
Food UnavailableAsk the customer to remove or replace the item.
Firestore ErrorShow retry option.
Invalid AddressRequest corrected address.
Image FailedDisplay placeholder image.
Order Creation FailedDo not show a false success message.

84. Performance Optimization

  • Use const widgets whenever possible.
  • Avoid unnecessary rebuilds.
  • Use ListView.builder for long lists.
  • Use GridView.builder for large food collections.
  • Cache remote images.
  • Paginate large Firestore collections.
  • Keep business logic outside UI widgets.
  • Dispose controllers when they are no longer needed.
  • Avoid expensive operations inside build().

85. Common Mistakes

  1. Putting all application code inside main.dart.
  2. Keeping cart state only inside one screen.
  3. Using hardcoded food data throughout multiple widgets.
  4. Ignoring loading and error states.
  5. Not validating checkout information.
  6. Using insecure Firestore rules.
  7. Performing unnecessary database reads.
  8. Ignoring responsive layouts.
  9. Not handling unavailable food items.
  10. Creating duplicate orders when the user taps the button multiple times.

86. Best Practices

  • Use reusable widgets.
  • Keep models separate from UI.
  • Keep Firebase operations inside service classes.
  • Use state management for shared application state.
  • Use meaningful variable and class names.
  • Validate all user input.
  • Handle asynchronous operations safely.
  • Show appropriate loading indicators.
  • Provide useful error messages.
  • Secure Firestore data.
  • Keep secrets and sensitive configuration out of public source code where appropriate.
  • Test important business logic independently.

87. Testing the Application

The application should be tested across different parts of the user journey.

TestExpected Result
RegistrationUser account is created successfully.
LoginUser enters the application.
Food SearchMatching food is displayed.
Add to CartFood appears in the cart.
Quantity UpdateCart amount changes correctly.
Remove ItemItem disappears from cart.
CheckoutRequired information is validated.
Place OrderOrder is saved successfully.
Order HistoryUser sees their orders.
LogoutUser returns to login screen.

88. Debugging Techniques

Use Flutter debugging tools to identify UI and logic problems.

flutter doctor
flutter analyze
flutter test
flutter run

Use debugPrint() instead of excessive regular print statements for debugging larger applications.

debugPrint('Cart total: $total');

89. Deployment Preparation

Before deploying the application:

  • Remove debug-only code.
  • Test release builds.
  • Verify Firebase configuration.
  • Verify Firestore security rules.
  • Optimize images.
  • Check application permissions.
  • Test authentication.
  • Test checkout and order creation.
  • Test different screen sizes.
  • Review application performance.

90. Flutter Build Commands

Build an Android APK:

flutter build apk

Build an Android App Bundle:

flutter build appbundle

Build for web:

flutter build web

91. Final Food Delivery Project Checklist

  • Flutter project created.
  • Project architecture configured.
  • Models created.
  • Reusable widgets created.
  • Home screen completed.
  • Restaurant screen completed.
  • Food detail screen completed.
  • Search implemented.
  • Cart implemented.
  • Quantity management implemented.
  • Checkout implemented.
  • Authentication implemented.
  • Firestore configured.
  • Food data connected.
  • Order data connected.
  • Order history implemented.
  • Order status implemented.
  • Profile screen implemented.
  • Responsive design tested.
  • Error handling added.
  • Security rules reviewed.
  • Release build tested.

92. Real-World Features You Can Add

After completing the basic application, the project can be expanded with additional features.

  • Live delivery tracking.
  • Google Maps integration.
  • Multiple saved addresses.
  • Restaurant search.
  • Advanced filtering.
  • Coupon system.
  • Discount management.
  • Wishlist.
  • Food ratings.
  • Restaurant reviews.
  • Push notifications.
  • Online payment gateway.
  • Order cancellation.
  • Scheduled delivery.
  • Restaurant admin panel.
  • Delivery partner application.

93. Advanced Application Architecture

As the project grows, a clean architecture approach can separate presentation, domain, and data responsibilities.

Presentation
    |
    +-- Screens
    +-- Widgets
    +-- Controllers / Providers
    |
    v
Domain
    |
    +-- Entities
    +-- Use Cases
    +-- Repository Contracts
    |
    v
Data
    |
    +-- Models
    +-- Repository Implementations
    +-- Firebase Services
    +-- Remote Data Sources

94. Why This Project Is Useful

This project demonstrates how Flutter concepts are combined in a real application instead of being used independently.

ConceptPractical Usage
WidgetsBuild the complete interface.
NavigationMove between application screens.
State ManagementManage cart and user state.
ModelsRepresent food, restaurants, and orders.
Firebase AuthManage users.
FirestoreStore application data.
StreamsDisplay real-time updates.
FormsCollect user information.
Responsive DesignSupport different screen sizes.
Error HandlingHandle failures gracefully.

95. Interview Questions Based on This Project

Question 1: Why should a food delivery application use state management?

State management allows shared data such as cart items, quantities, authentication state, and order information to be accessed and updated across multiple screens without tightly coupling those screens together.

Question 2: Why should models be created?

Models provide a structured representation of application data and make the code easier to understand, maintain, and transform between Firebase data and Flutter objects.

Question 3: Why use Firestore?

Firestore provides cloud-based document storage and supports real-time data synchronization, making it suitable for data such as restaurants, food items, users, and orders.

Question 4: How do you calculate the cart total?

The cart total can be calculated by multiplying each food item's price by its quantity and then adding the resulting values together.

Question 5: How can duplicate cart items be prevented?

Before adding a food item, check whether an item with the same unique food ID already exists in the cart. If it exists, increase its quantity instead of creating another cart entry.

Question 6: How can real-time order status be implemented?

Firestore document streams can listen for changes to the order document. When the restaurant or admin changes the order status, the customer interface can update automatically.

Question 7: Why should Firestore security rules be used?

Security rules control which authenticated users can read or write specific database resources. They help prevent unauthorized access to application data.

Question 8: What happens when an order is placed?

The application validates the cart and checkout information, calculates the final amount, creates an order record, clears the cart after successful creation, and navigates the user to an order confirmation or tracking screen.

Question 9: How can the application be made responsive?

Responsive layouts can use MediaQuery, LayoutBuilder, Expanded, Flexible, adaptive grids, and different layout structures based on available screen width.

Question 10: What improvements can be added to this project?

Advanced features can include online payments, maps, live delivery tracking, push notifications, coupons, ratings, reviews, scheduled orders, restaurant management, and delivery partner management.

96. Final Project Summary

The Flutter Food Delivery App is a complete practical project that demonstrates how to build a real-world mobile application using Flutter and Dart. The project starts with the fundamentals of Flutter UI and gradually introduces reusable components, navigation, models, cart state management, authentication, Firestore, order processing, real-time updates, responsive design, validation, error handling, and deployment preparation.

By completing this project, learners gain practical experience in connecting multiple Flutter concepts into one complete application workflow.

97. Skills You Learn From This Project

  • Flutter application architecture.
  • Dart object-oriented programming.
  • Reusable widget development.
  • Flutter navigation.
  • Form handling and validation.
  • State management.
  • Cart implementation.
  • Firebase Authentication.
  • Cloud Firestore.
  • Real-time application updates.
  • CRUD operations.
  • Responsive Flutter UI.
  • Error and loading state management.
  • Application performance optimization.
  • Production-oriented Flutter development.

98. Learning Resources

For structured Flutter learning and additional practical training, explore the JustAcademy Flutter Training Course.

To register for a course demo, visit Register for Flutter Course Demo.


99. Final Project Flow

Flutter Food Delivery App
        |
        +-- Authentication
        |      |
        |      +-- Register
        |      +-- Login
        |      +-- Logout
        |
        +-- Home
        |      |
        |      +-- Search
        |      +-- Categories
        |      +-- Restaurants
        |      +-- Popular Food
        |
        +-- Food
        |      |
        |      +-- Food List
        |      +-- Food Details
        |      +-- Add To Cart
        |
        +-- Cart
        |      |
        |      +-- Quantity
        |      +-- Remove Item
        |      +-- Subtotal
        |      +-- Delivery Fee
        |      +-- Tax
        |      +-- Total
        |
        +-- Checkout
        |      |
        |      +-- Address
        |      +-- Payment
        |      +-- Place Order
        |
        +-- Orders
        |      |
        |      +-- Order History
        |      +-- Order Status
        |      +-- Real-Time Updates
        |
        +-- Profile
               |
               +-- User Information
               +-- Addresses
               +-- Favorites
               +-- Logout

100. Conclusion

Building a Food Delivery App in Flutter is an excellent practical project for understanding complete application development. It combines UI design, reusable widgets, navigation, state management, Firebase Authentication, Firestore database operations, cart management, checkout processing, order tracking, responsive layouts, validation, error handling, and production preparation.

The same architecture can also be extended into larger applications such as restaurant management systems, grocery delivery applications, e-commerce platforms, cloud kitchens, meal subscription applications, and other marketplace-based applications.

Previous Next
whatsapp