Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🚀 Flutter FSD Counter

A Flutter counter application built with Feature-Sliced Design and Riverpod 3. Demonstrates a strict FSD layering where slices are domain-oriented, entities own the model + read side, and features own mutations (CUD).

📋 Project Overview

Flutter FSD Counter is a demo that applies Feature-Sliced Design (FSD) principles to a small Flutter app. It is intentionally minimal in domain (a single counter entity) so the focus stays on layer boundaries, generator-driven Riverpod, and redirect-based routing.

✨ Key Features

  • 🎯 FSD Architecture with explicit slice/segment naming
  • 🔥 Riverpod 3 + riverpod_generator@riverpod everywhere, zero hand-written providers
  • 🛣️ GoRouter redirect + refreshListenable — deep-link-safe status-driven navigation
  • 🛡️ Freezed 3 sealed unionsswitch pattern matching for state
  • 📱 Material 3 light / dark themes
  • 🧪 build_runner code generation (Freezed, JSON, Riverpod)

🛠️ Tech Stack

Environment

  • Flutter: 3.41.x stable
  • Dart: 3.11.x (SDK constraint ^3.8.1)

Core Libraries

  • flutter_riverpod: ^3.2.1
  • riverpod_annotation: ^4.0.2
  • go_router: ^17.2.3
  • dio: ^5.9.2
  • freezed_annotation: ^3.1.0
  • json_annotation: ^4.9.0

Dev / Tooling

  • build_runner: ^2.5.4
  • freezed: ^3.2.5
  • json_serializable: ^6.10.0
  • riverpod_generator: ^4.0.3
  • flutter_lints: ^5.0.0

🏗️ Project Structure

lib/
├── app/                         # Global configuration
│   ├── router/                  # GoRouter (redirect + refreshListenable)
│   └── theme/                   # Material 3 theme
├── entities/                    # Business model + read
│   └── counter/
│       ├── api/                 # CounterApi (mock-persisted state)
│       ├── model/               # Freezed types (model only — no providers)
│       ├── state/               # @riverpod Notifiers (read + state setters)
│       └── ui/                  # CounterDisplay (read-only widget)
├── features/                    # Mutations (CUD) per slice
│   ├── counter-actions/         # increment / decrement / reset
│   │   ├── model/               # CounterActionsNotifier
│   │   └── ui/                  # buttons
│   └── counter-session/         # start / stop
│       ├── model/               # CounterSessionNotifier
│       └── ui/                  # StartButton
├── pages/                       # Route-level composition
│   ├── home/{ui,helpers,index.dart}
│   └── counter/{ui,helpers,index.dart}
├── widgets/                     # Cross-feature reusable UI
│   └── app_bars/                # ConfigurableAppBar
└── shared/                      # Cross-cutting utilities
    ├── providers/               # dioProvider
    └── ui/                      # AppButton, LoadingView

🚀 Getting Started

Prerequisites

  • Flutter: 3.41.0 or higher
  • Dart: 3.11.0 or higher
  • VS Code or Android Studio recommended

Installation

git clone <repository-url>
cd flutter_fsd_counter

flutter pub get
dart run build_runner build --delete-conflicting-outputs

Run

flutter run                 # debug
flutter run --release       # release
flutter run -d chrome       # web

📱 Usage

Home Screen

  • Start screen shown when the app launches.
  • Tap Start Counter to navigate to the counter screen (routed automatically by CounterStatus).

Counter Screen

  • + Increment
  • Decrement
  • Reset (with confirmation dialog)
  • AppBar leading (←) Stop session → returns to home

State-Based Navigation

Navigation is driven by CounterStatus via GoRouter's redirect:

  • stopped / starting / error/
  • started/counter

Direct URL access (e.g. typing /counter in the web build while stopped) is automatically redirected back to /.

🏛️ FSD Architecture Guide

Layer Responsibilities

Layer Owns Talks to
app Router, theme, root app entities (for status), pages
entities Domain model, API, read-side Notifier, read-only UI shared
features Mutations (CUD), feature UI, calls into entity setters entities, shared
widgets Cross-feature reusable UI shared
pages Route composition of features/entities/widgets features, entities, widgets
shared Pure utilities, design system, infra providers

Slice Rules

  • Slice = business domain. Here the domain is counter. Both feature slices (counter-actions, counter-session) belong to that domain but represent distinct user intents.
  • Naming inside features: kebab-case-of-intent (e.g. counter-actions, counter-session) — not single-verb folders (increment/, decrement/, …).

Dependency Rules

  • Upper layers depend only on lower ones (pages → features → entities → shared).
  • No feature ↔ feature imports. Cross-feature integration happens at pages/.
  • Each slice/segment exposes an index.dart barrel.

🧪 Testing

flutter test
flutter test --coverage

🔧 Development Tools

dart run build_runner build --delete-conflicting-outputs   # one-shot
dart run build_runner watch --delete-conflicting-outputs   # watch
flutter analyze
flutter pub outdated

📦 Build

flutter build apk --release
flutter build appbundle --release
flutter build ios --release
flutter build web --release

🤝 Contributing

  1. Fork
  2. git checkout -b feature/AmazingFeature
  3. git commit -m 'feat: …'
  4. git push origin feature/AmazingFeature
  5. Open a PR

Coding Conventions

  • Respect FSD layering and slice = domain.
  • Use @riverpod generators; never write Provider/StateProvider by hand.
  • Notifiers must not take WidgetRef as a parameter.
  • Use Freezed sealed unions with switch pattern matching for state.
  • Expose slice externals through index.dart.

📜 License

MIT.

👥 Author

Hardy — Flutter Developer

🔗 Useful Links


⭐ If you find this project useful, please give it a star! ⭐

About

Flutter Counter Application with Feature-Sliced Design

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages