<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ hive - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ hive - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 25 Jul 2026 22:28:25 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/hive/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Store Data Locally Using Hive in Flutter ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, we’ll build a Flutter application that demonstrates how to perform CRUD (Create, Read, Update, Delete) operations using Hive for local data storage. Hive is a lightweight, fast key-value database written in pure Dart. Unlike SQLite,... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-store-data-locally-using-hive-in-flutter/</link>
                <guid isPermaLink="false">68c03b5738ba5d78dfb7c607</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flutter-aware ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hive ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Atuoha Anthony ]]>
                </dc:creator>
                <pubDate>Tue, 09 Sep 2025 14:36:07 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757428555303/4228b0b2-9edf-48af-a917-2535b6adffa3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, we’ll build a Flutter application that demonstrates how to perform CRUD (Create, Read, Update, Delete) operations using <a target="_blank" href="https://pub.dev/packages/hive">Hive</a> for local data storage.</p>
<p>Hive is a lightweight, fast key-value database written in pure Dart. Unlike SQLite, it doesn’t need a heavy SQL engine. It stores data in boxes, which you can think of as containers (similar to tables, but simpler).</p>
<p>For a small CRUD app like this, Hive is a great fit because:</p>
<ol>
<li><p>It’s offline-first, and all data is stored locally on the device – no internet required.</p>
</li>
<li><p>It’s type-safe and integrates well with Dart models (like our <code>Item</code>).</p>
</li>
<li><p>It’s much faster than SQLite for simple operations.</p>
</li>
<li><p>It has a Flutter-friendly API (<code>hive_flutter</code>) for things like reactive updates.</p>
</li>
</ol>
<p>Hive is great for a number of different use cases, like storing app preferences/settings, managing small to medium lists of structured data (like notes, tasks, or shopping lists), offline caching for API responses, and storing session or user profile data locally.</p>
<p>Here, Hive is powering the to-do/inventory-like list of items, which means everything (title, quantity) is stored locally and persists even after the app restarts.</p>
<p>By the end of this tutorial, you'll have a fully functional app that lets you add, edit, delete, and view items locally. I’ll provide clear explanations of the code along the way.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-project-setup">Step 1: Project Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-project-folder-structure">Step 2: Project Folder Structure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-implementing-the-application">Step 3: Implementing the Application</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-maindart">1. main.dart</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-itemdart-model">2. item.dart (Model)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-controllerdart-hive-controller">3. controller.dart (Hive Controller)</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-imports">Imports</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-class-definition-and-constructor">Class Definition and Constructor</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hive-box-reference">Hive Box Reference</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-fetching-data">Fetching Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-creating-an-item">Creating an Item</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-editing-an-item">Editing an Item</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-deleting-an-item">Deleting an Item</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-clearing-all-items">Clearing All Items</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-after-action-helper">After Action Helper</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-4-stringconstantsdart">4. string_constants.dart</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-statusdart-enum">5. status.dart (Enum)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-yesnodart-enum">6. yes_no.dart (Enum)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-7-toastdart">7. toast.dart</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-8-areyousuredart-confirmation-dialog">8. are_you_sure.dart (Confirmation Dialog)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-9-singlelisttiledart-list-item-widget">9. single_list_tile.dart (List Item Widget)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-10-mainscreendart-ui-state-management">10. main_screen.dart (UI + State Management)</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-screenshots">Screenshots</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we begin, make sure you have the following:</p>
<ol>
<li><p>Flutter SDK installed (version 3.0 or higher recommended).</p>
</li>
<li><p>Basic knowledge of Flutter: widgets, stateful/stateless widgets, and navigation.</p>
</li>
<li><p>A code editor like VS Code or Android Studio.</p>
</li>
<li><p>Familiarity with Dart classes, maps, and enums.</p>
</li>
</ol>
<h2 id="heading-step-1-project-setup">Step 1: Project Setup</h2>
<p>Start by creating a new Flutter project:</p>
<pre><code class="lang-bash">flutter create flutter_hive_crud
<span class="hljs-built_in">cd</span> flutter_hive_crud
</code></pre>
<p>Open <code>pubspec.yaml</code> and add the following dependencies:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
  <span class="hljs-attr">hive:</span> <span class="hljs-string">^2.2.3</span>
  <span class="hljs-attr">hive_flutter:</span> <span class="hljs-string">^1.1.0</span>
  <span class="hljs-attr">fluttertoast:</span> <span class="hljs-string">^8.2.12</span>
  <span class="hljs-attr">equatable:</span> <span class="hljs-string">^2.0.7</span>
</code></pre>
<p>Install them:</p>
<pre><code class="lang-bash">flutter pub get
</code></pre>
<ul>
<li><p><code>hive</code> – Lightweight key-value database for Flutter.</p>
</li>
<li><p><code>hive_flutter</code> – Flutter bindings for Hive.</p>
</li>
<li><p><code>fluttertoast</code> – Displays toast messages.</p>
</li>
<li><p><code>equatable</code> – Simplifies value equality in Dart objects.</p>
</li>
</ul>
<h2 id="heading-step-2-project-folder-structure">Step 2: Project Folder Structure</h2>
<p>Organize your project like this:</p>
<pre><code class="lang-dart">lib/
├── main.dart
├── model/
│   └── item.dart
├── controller/
│   └── controller.dart
├── constants/
│   ├── string_constants.dart
│   └── enums/
│       ├── status.dart
│       └── yes_no.dart
└── screens/
    ├── main_screen.dart
    └── widgets/
        ├── are_you_sure.dart
        ├── single_list_tile.dart
        ├── text_action.dart
        └── toast.dart
</code></pre>
<p>This structure keeps the app modular and maintainable.</p>
<h2 id="heading-step-3-implementing-the-application">Step 3: Implementing the Application</h2>
<p>We'll go through the process file by file, and I’ll explain what each piece does as we go.</p>
<h3 id="heading-1-maindart">1. <code>main.dart</code></h3>
<p>This is the entry point of the application. It initializes Hive and launches the app.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:hive_flutter/hive_flutter.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'screens/main_screen.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'constants/string_constants.dart'</span>;

Future&lt;<span class="hljs-keyword">void</span>&gt; main() <span class="hljs-keyword">async</span> {
  WidgetsFlutterBinding.ensureInitialized();

  <span class="hljs-comment">// Initialize Hive for Flutter</span>
  <span class="hljs-keyword">await</span> Hive.initFlutter();

  <span class="hljs-comment">// Open the Hive box to store items</span>
  <span class="hljs-keyword">await</span> Hive.openBox(StringConstants.hiveBox);

  runApp(<span class="hljs-keyword">const</span> MyApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> MyApp({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      title: <span class="hljs-string">'Flutter Hive CRUD'</span>,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.brown),
        useMaterial3: <span class="hljs-keyword">true</span>,
      ),
      home: <span class="hljs-keyword">const</span> MainScreen(),
    );
  }
}
</code></pre>
<p>Here’s what’s going on in this code:</p>
<ul>
<li><p><code>WidgetsFlutterBinding.ensureInitialized()</code> ensures Flutter widgets are ready.</p>
</li>
<li><p><code>Hive.initFlutter()</code> initializes Hive in Flutter.</p>
</li>
<li><p><code>Hive.openBox(...)</code> opens a persistent storage box.</p>
</li>
<li><p><code>MyApp</code> sets up the Material theme and main screen.</p>
</li>
</ul>
<h3 id="heading-2-itemdart-model">2. <code>item.dart</code> (Model)</h3>
<p>Since Hive stores data as key-value pairs, we need to decide how to represent each item (like a shopping list entry or product in stock). To keep our code organized, we’ll wrap each item in a Dart class called <code>Item</code>. That way, we can easily create, update, and convert items to Maps when saving them into Hive.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:equatable/equatable.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Item</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Equatable</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> title;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> quantity;

  <span class="hljs-keyword">const</span> Item({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.title, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.quantity});

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [title, quantity];

  <span class="hljs-comment">// Convert Item to Map for Hive storage</span>
  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toMap() {
    <span class="hljs-keyword">return</span> {<span class="hljs-string">'title'</span>: title, <span class="hljs-string">'quantity'</span>: quantity};
  }

  <span class="hljs-comment">// Create Item from Map</span>
  <span class="hljs-keyword">factory</span> Item.fromMap(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; map) {
    <span class="hljs-keyword">return</span> Item(title: map[<span class="hljs-string">'title'</span>], quantity: map[<span class="hljs-string">'quantity'</span>]);
  }
}
</code></pre>
<p>So every time we save or fetch data, we’re just converting between <code>Item</code> (class instance) and <code>Map</code> (Hive format).</p>
<p>Here’s what’s going on:</p>
<ul>
<li><p><code>Equatable</code> allows comparing items by value instead of reference.</p>
</li>
<li><p><code>toMap()</code> and <code>fromMap()</code> convert between Dart objects and the Hive storage format.</p>
</li>
</ul>
<h3 id="heading-3-controllerdart-hive-controller">3. <code>controller.dart</code> (Hive Controller)</h3>
<p>This controller handles all Hive CRUD operations and UI updates.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_hive_crud/constants/string_constants.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_hive_crud/screens/widgets/toast.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:hive_flutter/hive_flutter.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../constants/enums/status.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../model/item.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HiveController</span> </span>{
  <span class="hljs-keyword">final</span> BuildContext context;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">Function</span> fetchDataFunction;

  HiveController({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.context, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.fetchDataFunction});

  <span class="hljs-keyword">final</span> hiveBox = Hive.box(StringConstants.hiveBox);

  <span class="hljs-comment">// Fetch all items from Hive</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt;&gt; fetchData() {
    <span class="hljs-keyword">return</span> hiveBox.keys.map((key) {
      <span class="hljs-keyword">final</span> item = hiveBox.<span class="hljs-keyword">get</span>(key);
      <span class="hljs-keyword">return</span> {
        <span class="hljs-string">'key'</span>: key,
        <span class="hljs-string">'title'</span>: item[<span class="hljs-string">'title'</span>],
        <span class="hljs-string">'quantity'</span>: item[<span class="hljs-string">'quantity'</span>],
      };
    }).toList().reversed.toList();
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; createItem({<span class="hljs-keyword">required</span> Item item}) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> hiveBox.add(item.toMap());
      afterAction(<span class="hljs-string">'saved'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to create item'</span>, status: Status.error);
    }
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; editItem({<span class="hljs-keyword">required</span> Item item, <span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> itemKey}) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      hiveBox.put(itemKey, item.toMap());
      afterAction(<span class="hljs-string">'edited'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to edit item'</span>, status: Status.error);
    }
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; deleteItem({<span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> key}) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> hiveBox.delete(key);
      afterAction(<span class="hljs-string">'deleted'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to delete item'</span>, status: Status.error);
    }
  }

  Future&lt;<span class="hljs-keyword">void</span>&gt; clearItems() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> hiveBox.clear();
      afterAction(<span class="hljs-string">'cleared'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to clear items'</span>, status: Status.error);
    }
  }

  <span class="hljs-keyword">void</span> afterAction(<span class="hljs-built_in">String</span> keyword) {
    toastInfo(msg: <span class="hljs-string">'Item <span class="hljs-subst">$keyword</span> successfully'</span>, status: Status.success);
    fetchDataFunction(); <span class="hljs-comment">// Refresh UI</span>
    Navigator.of(context).pop(); <span class="hljs-comment">// Close modals</span>
  }
}
</code></pre>
<p>Let's break down this <code>HiveController</code> code block by block, explaining exactly what each section does and why it’s important.</p>
<h4 id="heading-imports">Imports:</h4>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_hive_crud/constants/string_constants.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_hive_crud/screens/widgets/toast.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:hive_flutter/hive_flutter.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../constants/enums/status.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../model/item.dart'</span>;
</code></pre>
<p>Here’s what’s happening:</p>
<ul>
<li><p><code>flutter/material.dart</code> – Provides Flutter’s material design widgets and utilities.</p>
</li>
<li><p><code>string_constants.dart</code> – Contains app-wide constants, for example the name of the Hive box.</p>
</li>
<li><p><code>toast.dart</code> – Utility to display toast messages for success or error feedback.</p>
</li>
<li><p><code>hive_flutter.dart</code> – Hive package integration with Flutter.</p>
</li>
<li><p><code>status.dart</code> – Enum representing status types (<code>error</code> or <code>success</code>) for toast messages.</p>
</li>
<li><p><code>item.dart</code> – The model class representing an individual item (title + quantity).</p>
</li>
</ul>
<p>These imports allow the controller to manage Hive data and interact with the UI.</p>
<h4 id="heading-class-definition-and-constructor">Class definition and constructor:</h4>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HiveController</span> </span>{
  <span class="hljs-keyword">final</span> BuildContext context;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">Function</span> fetchDataFunction;

  HiveController({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.context, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.fetchDataFunction});
</code></pre>
<p>Here’s what’s going on:</p>
<ul>
<li><p><code>HiveController</code> – This class manages all CRUD operations for Hive.</p>
</li>
<li><p><code>context</code> – The current Flutter <code>BuildContext</code>, used to navigate and show modals or dialogs.</p>
</li>
<li><p><code>fetchDataFunction</code> – A function passed from the UI that refreshes the list after performing any Hive operation.</p>
</li>
</ul>
<p>The constructor requires both parameters, ensuring that every instance of <code>HiveController</code> has access to the UI context and a way to refresh data.</p>
<h4 id="heading-hive-box-reference">Hive box reference:</h4>
<pre><code class="lang-dart">  <span class="hljs-keyword">final</span> hiveBox = Hive.box(StringConstants.hiveBox);
</code></pre>
<p>Here,</p>
<ul>
<li><p><code>hiveBox</code> is a reference to the Hive box defined in <code>StringConstants.hiveBox</code>.</p>
</li>
<li><p>A Hive box is like a key-value store where we save our items locally.</p>
</li>
<li><p>This allows the controller to interact with Hive without needing to re-open the box each time.</p>
</li>
</ul>
<h4 id="heading-fetching-data">Fetching data:</h4>
<pre><code class="lang-dart">  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt;&gt; fetchData() {
    <span class="hljs-keyword">return</span> hiveBox.keys.map((key) {
      <span class="hljs-keyword">final</span> item = hiveBox.<span class="hljs-keyword">get</span>(key);
      <span class="hljs-keyword">return</span> {
        <span class="hljs-string">'key'</span>: key,
        <span class="hljs-string">'title'</span>: item[<span class="hljs-string">'title'</span>],
        <span class="hljs-string">'quantity'</span>: item[<span class="hljs-string">'quantity'</span>],
      };
    }).toList().reversed.toList();
  }
</code></pre>
<p>Here’s what this code is doing:</p>
<ul>
<li><p><code>hiveBox.keys</code> – Retrieves all the keys stored in the Hive box.</p>
</li>
<li><p><code>.map((key) =&gt; ...)</code> – Iterates through each key and fetches the associated item.</p>
</li>
<li><p>Converts each item into a Map containing:</p>
<ul>
<li><p><code>'key'</code> – The unique Hive key (used for updates/deletes).</p>
</li>
<li><p><code>'title'</code> – Item title.</p>
</li>
<li><p><code>'quantity'</code> – Item quantity.</p>
</li>
</ul>
</li>
<li><p><code>.toList().reversed.toList()</code> – Converts the mapped iterable to a list and reverses it so <strong>newest items appear first</strong>.</p>
</li>
</ul>
<p>This method returns a list of items ready for display in the UI.</p>
<h4 id="heading-creating-an-item">Creating an item:</h4>
<pre><code class="lang-dart">  Future&lt;<span class="hljs-keyword">void</span>&gt; createItem({<span class="hljs-keyword">required</span> Item item}) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> hiveBox.add(item.toMap());
      afterAction(<span class="hljs-string">'saved'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to create item'</span>, status: Status.error);
    }
  }
</code></pre>
<p>In this code,</p>
<ul>
<li><p><code>item.toMap()</code> – Converts the <code>Item</code> object to a Map so Hive can store it.</p>
</li>
<li><p><code>hiveBox.add(...)</code> – Adds a new entry to the Hive box, generating a unique key automatically.</p>
</li>
<li><p><code>afterAction('saved')</code> – Shows a success toast, refreshes the UI, and closes any open modal.</p>
</li>
<li><p>The <code>catch</code> block handles errors and displays a toast if something goes wrong.</p>
</li>
</ul>
<h4 id="heading-editing-an-item">Editing an item:</h4>
<pre><code class="lang-dart">  Future&lt;<span class="hljs-keyword">void</span>&gt; editItem({<span class="hljs-keyword">required</span> Item item, <span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> itemKey}) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      hiveBox.put(itemKey, item.toMap());
      afterAction(<span class="hljs-string">'edited'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to edit item'</span>, status: Status.error);
    }
  }
</code></pre>
<p>In this code,</p>
<ul>
<li><p><code>hiveBox.put(itemKey, item.toMap())</code> – Updates the item at the specific key with the new data.</p>
</li>
<li><p><code>afterAction('edited')</code> – Handles feedback and UI updates.</p>
</li>
<li><p>The <code>catch</code> block handles any errors during the edit process.</p>
</li>
</ul>
<h4 id="heading-deleting-an-item">Deleting an item:</h4>
<pre><code class="lang-dart">  Future&lt;<span class="hljs-keyword">void</span>&gt; deleteItem({<span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> key}) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> hiveBox.delete(key);
      afterAction(<span class="hljs-string">'deleted'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to delete item'</span>, status: Status.error);
    }
  }
</code></pre>
<p>Here,</p>
<ul>
<li><p><code>hiveBox.delete(key)</code> – Removes the item associated with the specified key from Hive.</p>
</li>
<li><p>Calls <code>afterAction('deleted')</code> to refresh UI and show a success message.</p>
</li>
<li><p>Errors are handled with a toast.</p>
</li>
</ul>
<h4 id="heading-clearing-all-items">Clearing all items:</h4>
<pre><code class="lang-dart">  Future&lt;<span class="hljs-keyword">void</span>&gt; clearItems() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> hiveBox.clear();
      afterAction(<span class="hljs-string">'cleared'</span>);
    } <span class="hljs-keyword">catch</span> (e) {
      toastInfo(msg: <span class="hljs-string">'Failed to clear items'</span>, status: Status.error);
    }
  }
</code></pre>
<p>Here’s what’s happening:</p>
<ul>
<li><p><code>hiveBox.clear()</code> – Deletes <strong>all items</strong> in the Hive box.</p>
</li>
<li><p>Useful for “Clear All” functionality in the app.</p>
</li>
<li><p>Success and errors are handled the same way as other actions.</p>
</li>
</ul>
<h4 id="heading-after-action-helper">After action helper:</h4>
<pre><code class="lang-dart">  <span class="hljs-keyword">void</span> afterAction(<span class="hljs-built_in">String</span> keyword) {
    toastInfo(msg: <span class="hljs-string">'Item <span class="hljs-subst">$keyword</span> successfully'</span>, status: Status.success);
    fetchDataFunction(); <span class="hljs-comment">// Refresh UI</span>
    Navigator.of(context).pop(); <span class="hljs-comment">// Close modals</span>
  }
</code></pre>
<p>Here’s what’s going on:</p>
<ul>
<li><p><code>toastInfo(...)</code> – Displays a success toast, for example, “Item saved successfully.”</p>
</li>
<li><p><code>fetchDataFunction()</code> – Calls the function passed from the UI to reload the list.</p>
</li>
<li><p><code>Navigator.of(context).pop()</code> – Closes any open modal or dialog (like the item form).</p>
</li>
</ul>
<p>This method avoids repetition, centralizing the logic after any CRUD operation.</p>
<p><strong>Summary of HiveController Responsibilities:</strong></p>
<ol>
<li><p>Fetch items from Hive for UI display.</p>
</li>
<li><p>Create, update, delete, and clear items.</p>
</li>
<li><p>Provide user feedback via toast messages.</p>
</li>
<li><p>Refresh the UI automatically after any data change.</p>
</li>
<li><p>Manage modals and dialogs with context.</p>
</li>
<li><p><code>HiveController</code> abstracts Hive operations for cleaner UI code.</p>
</li>
<li><p>Methods: <code>createItem</code>, <code>editItem</code>, <code>deleteItem</code>, <code>clearItems</code>.</p>
</li>
<li><p><code>afterAction</code> updates the UI and shows success messages.</p>
</li>
</ol>
<h3 id="heading-4-stringconstantsdart">4. <code>string_constants.dart</code></h3>
<p>This is centralized storage for string constants like Hive box names.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringConstants</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> hiveBox = <span class="hljs-string">'items'</span>;
}
</code></pre>
<p>In this code:</p>
<ul>
<li><p><code>class StringConstants</code> – Defines a class that’s only used to group constant values together.</p>
</li>
<li><p><code>static</code> – Means you don’t need to create an instance of <code>StringConstants</code> to use it. You can access it directly as <code>StringConstants.hiveBox</code>.</p>
</li>
<li><p><code>const</code> – Makes it a compile-time constant, so it can’t be modified anywhere in your code.</p>
</li>
<li><p><code>'items'</code> – This is just a string value. In this case, it’s the name of the Hive box you’ll be opening.</p>
</li>
</ul>
<h3 id="heading-5-statusdart-enum">5. <code>status.dart</code> (Enum)</h3>
<pre><code class="lang-dart"><span class="hljs-keyword">enum</span> Status { error, success }
</code></pre>
<p>In this code:</p>
<ul>
<li><p><code>enum</code> – Short for <strong>enumeration</strong>. It’s a special type that lets you define a fixed set of named values.</p>
</li>
<li><p><code>Status</code> – The name of the enum.</p>
</li>
<li><p><code>{ error, success }</code> – The possible values this enum can take.</p>
</li>
</ul>
<p>So <code>Status</code> is now a custom type with only <strong>two valid values</strong>:</p>
<pre><code class="lang-dart">Status.error
Status.success
</code></pre>
<h4 id="heading-why-use-it-here">Why use it here?</h4>
<p>Instead of passing around plain strings like <code>"error"</code> or <code>"success"</code> (which are easy to misspell), the code can use <code>Status.error</code> or <code>Status.success</code>.</p>
<p>For example, when showing a toast:</p>
<pre><code class="lang-python">toastInfo(msg: <span class="hljs-string">'Item deleted'</span>, status: Status.success);
</code></pre>
<p>Or:</p>
<pre><code class="lang-dart">toastInfo(msg: <span class="hljs-string">'Failed to delete item'</span>, status: Status.error);
</code></pre>
<p>This makes the code safer (you can’t accidentally pass <code>"sucess"</code> and break things), clearer (you can see the intent immediately), and easier to maintain (if you add more statuses later like <code>warning</code> or <code>info</code>, it’s just one place to update).</p>
<h3 id="heading-6-yesnodart-enum">6. <code>yes_no.dart</code> (Enum)</h3>
<pre><code class="lang-dart"><span class="hljs-keyword">enum</span> YesNo { yes, no }
</code></pre>
<ul>
<li><p>Defines a new type called <code>YesNo</code>.</p>
</li>
<li><p>It can only ever have <strong>two possible values</strong>:</p>
<ul>
<li><p><code>YesNo.yes</code></p>
</li>
<li><p><code>YesNo.no</code></p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-why-use-it">Why use it?</h4>
<p>Instead of passing around booleans (<code>true</code> / <code>false</code>) or strings (<code>"yes"</code> / <code>"no"</code>), you can use this enum to make your intent much clearer in code.</p>
<p>For example:</p>
<pre><code class="lang-dart">YesNo userAccepted = YesNo.yes;

<span class="hljs-keyword">if</span> (userAccepted == YesNo.yes) {
  <span class="hljs-built_in">print</span>(<span class="hljs-string">"User agreed!"</span>);
} <span class="hljs-keyword">else</span> {
  <span class="hljs-built_in">print</span>(<span class="hljs-string">"User declined!"</span>);
}
</code></pre>
<p>This is more descriptive than using a plain <code>bool</code> where you’d have to guess what <code>true</code> or <code>false</code> means in context.</p>
<h4 id="heading-common-use-cases">Common use cases:</h4>
<ul>
<li><p>Confirmations (for example, <em>“Do you want to save this file?”</em>).</p>
</li>
<li><p>Settings toggles (for example, <em>“Enable notifications?”</em>).</p>
</li>
<li><p>API responses that return <code>"yes"</code> / <code>"no"</code> as strings. You can map them to this enum for safer handling.</p>
</li>
</ul>
<h3 id="heading-7-toastdart">7. <code>toast.dart</code></h3>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:fluttertoast/fluttertoast.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../../../constants/enums/status.dart'</span>;

<span class="hljs-keyword">void</span> toastInfo({<span class="hljs-keyword">required</span> <span class="hljs-built_in">String</span> msg, <span class="hljs-keyword">required</span> Status status}) {
  Fluttertoast.showToast(
    msg: msg,
    backgroundColor: status == Status.error ? Colors.red : Colors.green,
    toastLength: Toast.LENGTH_LONG,
    gravity: ToastGravity.TOP,
  );
}
</code></pre>
<p>This is a helper function for showing toast messages in your Flutter app.</p>
<p>A <strong>toast</strong> is a small, temporary popup message (usually at the bottom or top of the screen) used to quickly notify the user about something. For example, you might have <em>“Item saved successfully”</em> or <em>“Error deleting item”</em>.</p>
<h3 id="heading-8-areyousuredart-confirmation-dialog">8. <code>are_you_sure.dart</code> (Confirmation Dialog)</h3>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:io'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/cupertino.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

Future&lt;<span class="hljs-keyword">void</span>&gt; areYouSureDialog({
  <span class="hljs-keyword">required</span> <span class="hljs-built_in">String</span> title,
  <span class="hljs-keyword">required</span> <span class="hljs-built_in">String</span> content,
  <span class="hljs-keyword">required</span> BuildContext context,
  <span class="hljs-keyword">required</span> <span class="hljs-built_in">Function</span> action,
  <span class="hljs-built_in">bool</span> isKeyInvolved = <span class="hljs-keyword">false</span>,
  <span class="hljs-built_in">int</span> key = <span class="hljs-number">0</span>,
}) {
  <span class="hljs-keyword">return</span> showDialog(
    context: context,
    builder: (context) =&gt; Platform.isIOS
        ? CupertinoAlertDialog(
            title: Text(title),
            content: Text(content),
            actions: [
              CupertinoDialogAction(
                  onPressed: () =&gt;
                      isKeyInvolved ? action(key: key) : action(),
                  child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Yes'</span>)),
              CupertinoDialogAction(
                  onPressed: () =&gt; Navigator.of(context).pop(),
                  child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Dismiss'</span>)),
            ],
          )
        : AlertDialog(
            title: Text(title),
            content: Text(content),
            actions: [
              ElevatedButton(
                  onPressed: () =&gt;
                      isKeyInvolved ? action(key: key) : action(),
                  child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Yes'</span>)),
              ElevatedButton(
                  onPressed: () =&gt; Navigator.of(context).pop(),
                  child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Dismiss'</span>)),
            ],
          ),
  );
}
</code></pre>
<p>This code handles user confirmations for actions like delete or clear.</p>
<p>This function shows a platform-aware confirmation dialog (<code>Are you sure?</code>) that:</p>
<ol>
<li><p>Works on iOS with a <code>CupertinoAlertDialog</code>.</p>
</li>
<li><p>Works on Android/others with a Material <code>AlertDialog</code>.</p>
</li>
<li><p>Calls a provided <code>action</code> when the user presses Yes.</p>
</li>
<li><p>Closes the dialog when the user presses Dismiss.</p>
</li>
<li><p>Optionally passes a <code>key</code> into the action function.</p>
</li>
</ol>
<h3 id="heading-9-singlelisttiledart-list-item-widget">9. <code>single_list_tile.dart</code> (List Item Widget)</h3>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../../model/item.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'text_action.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../../constants/enums/yes_no.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SingleListItem</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">final</span> Item item;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> itemKey;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">Function</span> editHandle;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">Function</span> deleteDialog;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">Function</span> deleteItem;

  <span class="hljs-keyword">const</span> SingleListItem({
    <span class="hljs-keyword">super</span>.key,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.item,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.itemKey,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.editHandle,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.deleteDialog,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.deleteItem,
  });

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Dismissible(
      key: ValueKey(itemKey),
      confirmDismiss: (_) =&gt; showDialog(
        context: context,
        builder: (_) =&gt; AlertDialog(
          title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Are you sure?'</span>),
          content: Text(<span class="hljs-string">'Delete <span class="hljs-subst">${item.title}</span>?'</span>),
          actions: [
            textAction(<span class="hljs-string">'Yes'</span>, YesNo.yes, context),
            textAction(<span class="hljs-string">'No'</span>, YesNo.no, context),
          ],
        ),
      ),
      onDismissed: (_) =&gt; deleteItem(key: itemKey),
      background: Container(
        color: Colors.red,
        alignment: Alignment.centerRight,
        padding: <span class="hljs-keyword">const</span> EdgeInsets.only(right: <span class="hljs-number">20</span>),
        child: <span class="hljs-keyword">const</span> Icon(Icons.delete, color: Colors.white),
      ),
      child: ListTile(
        title: Text(item.title),
        subtitle: Text(item.quantity.toString()),
        trailing: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            IconButton(onPressed: () =&gt; editHandle(item: item, key: itemKey), icon: <span class="hljs-keyword">const</span> Icon(Icons.edit)),
            IconButton(onPressed: () =&gt; deleteDialog(key: itemKey), icon: <span class="hljs-keyword">const</span> Icon(Icons.delete)),
          ],
        ),
      ),
    );
  }
}
</code></pre>
<p>This code represents each list item with edit/delete options and swipe-to-delete functionality.</p>
<p>This widget represents <strong>one item</strong> (like a row in a shopping list, todo list, inventory app, and so on) with:</p>
<ol>
<li><p>Swipe-to-delete functionality.</p>
</li>
<li><p>Edit and delete buttons.</p>
</li>
<li><p>A confirmation dialog before dismissing</p>
</li>
</ol>
<h3 id="heading-10-mainscreendart-ui-state-management">10. <code>main_screen.dart</code> (UI + State Management)</h3>
<p>This is the main screen that puts everything together, including forms, lists, and modals.<br>Due to length, the full explanation is already well-commented in the original code, covering:</p>
<ul>
<li><p><code>itemModal()</code> – Bottom sheet form for create/edit.</p>
</li>
<li><p><code>fetchData()</code> – Load items from Hive.</p>
</li>
<li><p><code>editHandle()</code> – Load item for editing.</p>
</li>
<li><p><code>deleteDialog()</code> – Confirm delete.</p>
</li>
<li><p><code>clearAllDialog()</code> – Confirm clearing all items.</p>
</li>
</ul>
<h2 id="heading-screenshots">Screenshots</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703246520284/6d8ab811-24f4-4482-82f3-a1ab37eff384.png" alt="screenshot of a populated list " class="image--center mx-auto" width="1918" height="1002" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703246525459/80ac292a-271d-4adf-b2bb-7dfbdb57170d.png" alt="screenshot of adding a new item" class="image--center mx-auto" width="1918" height="1002" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703246531588/5e88c1ca-1ae0-4655-be16-e6646ef5e97d.png" alt="screenshot of a dialog asking to confirm if you want to delete an item in iOS" class="image--center mx-auto" width="1918" height="1002" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703246535449/aa2f7469-bbab-4c5d-bf8d-25ce9ba01743.png" alt="screenshot of a confirmation dialog box of deletion in Android" class="image--center mx-auto" width="1918" height="1002" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703246539025/233ddf98-62c8-4c0f-89b0-344be26dfabe.png" alt="screenshot of dialog box of clearing items " class="image--center mx-auto" width="1918" height="1002" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703246543769/13c5ecba-0916-4083-ab00-e756543f7643.png" alt="screenshot of a toast notification" class="image--center mx-auto" width="1918" height="1002" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703246547869/33aae852-e656-43a6-b41b-887cedd81e47.png" alt="screenshot of an empty state." class="image--center mx-auto" width="1918" height="1002" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You now have a fully functional Flutter app with Hive for local data persistence. Your app can:</p>
<ul>
<li><p>Create, Read, Update, Delete items.</p>
</li>
<li><p>Show toast messages for feedback.</p>
</li>
<li><p>Confirm actions with dialogs for Android and iOS.</p>
</li>
<li><p>Clean, modular architecture with controllers, models, and widgets.</p>
</li>
</ul>
<p>You can explore Hive further in the <a target="_blank" href="https://pub.dev/packages/hive">Hive Package Documentation</a> if you want to learn more.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
