Skip to content

Repository files navigation

Candy Store State 🍬

A clean, lightweight Flutter application demonstrating Vanilla State Management patterns. This app serves as a practical example of how to manage complex application state (like a shopping cart) using only the built-in tools provided by the Flutter SDK, without relying on third-party libraries like Provider, Riverpod, or Bloc.

🚀 Overview

The Candy Store app allows users to browse a delicious selection of sweets, add them to a shopping cart, and manage their selections. The primary focus of this project is to illustrate the "Flutter Way" of handling state using:

  • ChangeNotifier for business logic and state notifications.
  • InheritedWidget for efficient dependency injection and data propagation.
  • ListenableBuilder for targeted UI rebuilds.

✨ Features

  • Product Catalog: A scrollable list of various candies with descriptions, images, and prices.
  • Dynamic Shopping Cart:
    • Add items to the cart directly from the product list.
    • Increment/decrement item quantities within the cart.
    • Real-time updates of total item count and total price.
  • Persistent State: The cart state is maintained across different screens (Products Page and Cart Page) using a centralized provider.
  • Responsive UI: Built with Material Design 3 principles.

🛠️ Technical Implementation

State Management Strategy

The app follows a "Vanilla" approach to state management:

  1. Model/Notifier (CartNotifier): Extends ChangeNotifier. It holds the cart items and encapsulates the logic for adding/removing products. Whenever the state changes, it calls notifyListeners().
  2. Provider (CartProvider): A custom InheritedWidget that wraps the CartNotifier. This allows any widget in the tree to access the cart state via CartProvider.of(context).
  3. UI Updates: Widgets use ListenableBuilder to listen to specific changes in the CartNotifier, ensuring that only the necessary parts of the UI (like the cart badge or the list items) are rebuilt.

🏁 Getting Started

Prerequisites

  • Flutter SDK installed on your machine.
  • A code editor (Android Studio, VS Code, or IntelliJ).

Installation

  1. Clone the repository:
    git clone https://github.com/your-username/candy-store-state.git
    cd candy-store-state
  2. Get dependencies:
    flutter pub get
  3. Run the app:
    flutter run

🧠 Lessons Learned: The Vanilla Vantage Point

Building this app using only vanilla Flutter tools was an enlightening experience. Here are the key lessons I learned from this perspective:

1. Understanding the "Magic"

When I use libraries like Provider or Riverpod, a lot of the heavy lifting is hidden behind elegant APIs. By implementing InheritedWidget myself, I truly understood how Flutter's BuildContext works and how the framework propagates data down the widget tree. It removed the "black box" feeling and gave me a deeper appreciation for the framework's architecture.

2. The Power of ChangeNotifier

I realized that for many apps, ChangeNotifier is more than enough. It's simple, intuitive, and extremely powerful when paired with ListenableBuilder. I learned that I don't always need complex state machines or streams; sometimes, a simple "hey, something changed" is the most efficient way to handle UI updates.

3. Precision Rebuilds Matter

Without a high-level library managing everything, I had to be very intentional about where I placed my builders. I learned to use ListenableBuilder at the leaf nodes of my widget tree to prevent unnecessary rebuilds of large layouts. This "manual" optimization taught me to be more mindful of performance from the start.

4. Dependency Injection is just a Widget

I used to think of Dependency Injection (DI) as a separate architectural layer. Building the CartProvider taught me that in Flutter, DI is just another widget. The tree is the architecture. Being able to inject my CartNotifier at the root and access it anywhere via context proved that Flutter’s native capabilities are incredibly robust.

5. Less is Sometimes More

By avoiding external packages, the project has zero external dependencies (beyond standard Flutter). This results in smaller binary sizes, fewer versioning conflicts, and a codebase that is easier to maintain long-term as the framework evolves. I learned that "standard" doesn't mean "basic"—it means "reliable."

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages