Open In App

Flutter – Build a Inventory Management App

Last Updated : 26 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Inventory management is a crucial aspect of any business. With the power of Flutter, we can create a simple yet effective inventory management app. In this tutorial, we’ll build a basic inventory manager using Flutter and local storage. A sample video is given below to get an idea about what we are going to do in this article.

Step By Step Implementation

Step 1: Create a project

Let’s start by creating a new Flutter project. Open the terminal and run:

flutter create inventory_manager
cd inventory_manager

Step 2: Add packages

In pubspec.yaml file, add shared_preferences as a dependency in the dependencies section, and press Ctrl + S, in order to install it and use it in the project.

Capture

Step 3: Define Item Model

First, let’s define the model for inventory item which takes name of the item to be added and its quantity.

Dart




class Item {
    
  final String name;
  final int quantity;
  
  Item({required this.name, required this.quantity});
}


Step 4: Create Inventory Class

Create an Inventory class that will be instantiated with list of Items, and consists of functions to perform addition, update, and delete operation on items.

Dart




class Inventory {
    
  List<Item> items;
  
  Inventory(this.items);
  
  void addItem(Item item) {
    items.add(item);
  }
  
  void editItem(int index, Item item) {
    items[index] = item;
  }
  
  void deleteItem(int index) {
    items.removeAt(index);
  }
}


Step 5: Create CRUD functions

Let’s create following functions:

  • loadInventory() – This asynchronous function loads the inventory from local storage using SharedPreferences. It retrieves a list of items as strings, splits them into parts (name and quantity), and creates Item objects. The resulting list is used to initialize the inventory variable.
  • saveInventory() – Saves the current inventory to local storage using SharedPreferences. It converts each Item to a formatted string (name:quantity) and stores the list.
  • addItem() – This function adds a new item to the inventory. It reads the name and quantity from controllers, creates an Item object, adds it to the inventory, and then clears the input fields.
  • editItem() – Similar to adding an item, this function edits an existing item in the inventory. It reads the updated name and quantity from controllers, modifies the item in the inventory, clears input fields, saves the updated inventory, and resets the selected index.
  • deleteItem() – Deletes an item from the inventory at the specified index, saves the updated inventory to local storage.

Dart




late Inventory inventory;
 
Future<void> loadInventory() async {
   final prefs = await SharedPreferences.getInstance();
   final items = prefs.getStringList('inventory') ?? [];
   setState(() {
     inventory = Inventory(
       items.map((item) {
         final parts = item.split(':');
         return Item(name: parts[0], quantity: int.parse(parts[1]));
       }).toList(),
     );
   });
 }
 
Future<void> saveInventory() async {
   final prefs = await SharedPreferences.getInstance();
   final items = inventory!.items.map((item) => '${item.name}:${item.quantity}').toList();
   prefs.setStringList('inventory', items);
 }
 
 void addItem() {
   final name = itemNameController.text;
   final quantity = int.tryParse(quantityController.text) ?? 0;
 
   if (name.isNotEmpty && quantity > 0) {
     setState(() {
       inventory!.addItem(Item(name: name, quantity: quantity));
       itemNameController.clear();
       quantityController.clear();
       saveInventory();
     });
   }
 }
 
 void editItem() {
   final name = itemNameController.text;
   final quantity = int.tryParse(quantityController.text) ?? 0;
 
   if (name.isNotEmpty && quantity > 0) {
     setState(() {
       inventory!.editItem(selectedIndex, Item(name: name, quantity: quantity));
       itemNameController.clear();
       quantityController.clear();
       saveInventory();
       selectedIndex = -1;
     });
   }
 }
 
 void deleteItem(int index) {
   setState(() {
     inventory!.deleteItem(index);
     saveInventory();
   });
 }


Step 6: Create Edit Dialog

Create an alert dialog to edit items.

Dart




void showEditDialog(int index) {
    
    itemNameController.text = inventory!.items[index].name;
    quantityController.text = inventory!.items[index].quantity.toString();
    selectedIndex = index;
  
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Edit Item'),
          content: SingleChildScrollView(
            child: Column(
              children: [
                TextField(
                  controller: itemNameController,
                  decoration: InputDecoration(labelText: 'Item Name'),
                ),
                TextField(
                  controller: quantityController,
                  keyboardType: TextInputType.number,
                  decoration: InputDecoration(labelText: 'Quantity'),
                ),
              ],
            ),
          ),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('Cancel'),
            ),
            ElevatedButton(
              onPressed: () {
                editItem();
                Navigator.of(context).pop();
              },
              child: Text('Save'),
            ),
          ],
        );
      },
    );
  }


Step 7: Create ListView

Using ListView display inventory items along with edit and delete icons.

Dart




ListView.builder(
              itemCount: inventory!.items.length,
              itemBuilder: (context, index) {
                final item = inventory!.items[index];
                return Card(
                  child: ListTile(
                    title: Text(item.name),
                    subtitle: Text('Quantity: ${item.quantity}'),
                    trailing: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        IconButton(
                          icon: Icon(Icons.edit),
                          onPressed: () {
                            showEditDialog(index);
                          },
                        ),
                        IconButton(
                          icon: Icon(Icons.delete),
                          onPressed: () {
                            deleteItem(index);
                          },
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),


Complete Source Code

Dart




import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
  
void main() {
  runApp(MyApp());
}
  
class Item {
  final String name;
  final int quantity;
  
  Item({required this.name, required this.quantity});
}
  
class Inventory {
  List<Item> items;
  
  Inventory(this.items);
  
  void addItem(Item item) {
    items.add(item);
  }
  
  void editItem(int index, Item item) {
    items[index] = item;
  }
  
  void deleteItem(int index) {
    items.removeAt(index);
  }
}
  
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'GFG Inventory Manager',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: InventoryScreen(),
    );
  }
}
  
class InventoryScreen extends StatefulWidget {
  @override
  _InventoryScreenState createState() => _InventoryScreenState();
}
  
class _InventoryScreenState extends State<InventoryScreen> {
  late Inventory inventory;
  final itemNameController = TextEditingController();
  final quantityController = TextEditingController();
  
 int selectedIndex = -1;
  
  @override
  void initState() {
    super.initState();
    loadInventory();
  }
  
  Future<void> loadInventory() async {
    final prefs = await SharedPreferences.getInstance();
    final items = prefs.getStringList('inventory') ?? [];
    setState(() {
      inventory = Inventory(
        items.map((item) {
          final parts = item.split(':');
          return Item(name: parts[0], quantity: int.parse(parts[1]));
        }).toList(),
      );
    });
  }
  
  Future<void> saveInventory() async {
    final prefs = await SharedPreferences.getInstance();
    final items = inventory!.items.map((item) => '${item.name}:${item.quantity}').toList();
    prefs.setStringList('inventory', items);
  }
  
  void addItem() {
    final name = itemNameController.text;
    final quantity = int.tryParse(quantityController.text) ?? 0;
  
    if (name.isNotEmpty && quantity > 0) {
      setState(() {
        inventory!.addItem(Item(name: name, quantity: quantity));
        itemNameController.clear();
        quantityController.clear();
        saveInventory();
      });
    }
  }
  
  void editItem() {
    final name = itemNameController.text;
    final quantity = int.tryParse(quantityController.text) ?? 0;
  
    if (name.isNotEmpty && quantity > 0) {
      setState(() {
        inventory!.editItem(selectedIndex, Item(name: name, quantity: quantity));
        itemNameController.clear();
        quantityController.clear();
        saveInventory();
        selectedIndex = -1;
      });
    }
  }
  
  void deleteItem(int index) {
    setState(() {
      inventory!.deleteItem(index);
      saveInventory();
    });
  }
  
  void showEditDialog(int index) {
    itemNameController.text = inventory!.items[index].name;
    quantityController.text = inventory!.items[index].quantity.toString();
    selectedIndex = index;
  
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Edit Item'),
          content: SingleChildScrollView(
            child: Column(
              children: [
                TextField(
                  controller: itemNameController,
                  decoration: InputDecoration(labelText: 'Item Name'),
                ),
                TextField(
                  controller: quantityController,
                  keyboardType: TextInputType.number,
                  decoration: InputDecoration(labelText: 'Quantity'),
                ),
              ],
            ),
          ),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('Cancel'),
            ),
            ElevatedButton(
              onPressed: () {
                editItem();
                Navigator.of(context).pop();
              },
              child: Text('Save'),
            ),
          ],
        );
      },
    );
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GFG Inventory Manager'),
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: inventory!.items.length,
              itemBuilder: (context, index) {
                final item = inventory!.items[index];
                return Card(
                  child: ListTile(
                    title: Text(item.name),
                    subtitle: Text('Quantity: ${item.quantity}'),
                    trailing: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        IconButton(
                          icon: Icon(Icons.edit),
                          onPressed: () {
                            showEditDialog(index);
                          },
                        ),
                        IconButton(
                          icon: Icon(Icons.delete),
                          onPressed: () {
                            deleteItem(index);
                          },
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: [
                TextField(
                  controller: itemNameController,
                  decoration: InputDecoration(
                      
    border: OutlineInputBorder(),
                     labelText: 'Item Name'),
                ),
                SizedBox(height: 20),
                TextField(
                  controller: quantityController,
                    
                  keyboardType: TextInputType.number,
                  decoration: InputDecoration(
                      
    border: OutlineInputBorder(),
                    labelText: 'Quantity'),
                ),
                SizedBox(height: 16),
                ElevatedButton(
                  onPressed: selectedIndex == -1 ? addItem : editItem,
                  child: Text(selectedIndex == -1 ? 'Add Item' : 'Save'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}


Output:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads