๐ก Popsicle โ Simple. Reactive. Composable
Popsicle
is a lightweight, extensible state management and dependency injection (DI) framework for Flutter, built with simplicity and power in mind. Designed for developers who want full control without boilerplate,Popsicle
unifies state, DI, and lifecycle management under one clean architecture.
๐ Features
- โ
Reactive & composable state management (
ReactiveState
,AsyncState
,StreamState
) - โ Built-in dependency injection without global variables
- โ
Zero-boilerplate DI with centralized configuration via
AppDI
class - โ Lifecycle-aware state observers & disposal
- โ Middleware support for state transformation or interception
- โ Supports Flutter & Dart CLI applications
- โ Designed for both small and large-scale apps
- โ Modular architecture for easy extensibility
๐ฆ Installation
Add popsicle
to your pubspec.yaml
:
dependencies:
popsicle: ^1.0.0
Then run:
flutter pub get
๐ง Philosophy
Popsicle is inspired by the idea of:
f(State) => UI
We believe the UI should be a pure function of state โ with your logic encapsulated, testable, and clean.
๐ ๏ธ Getting Started
1. Extend AppDI
to register dependencies
class AppDI extends DIConfigurator {
static final authService = container.reg<AuthService>(AuthServiceImpl());
static final logger = container.regLazy(() => Logger());
}
2. Inject Popsicle in your app root (Optional ๐)
void main() {
runApp(
PopsicleDI(
app: const MyApp(),
inject: () => AppDI(),
),
);
}
3. Use anywhere (without context!)
final auth = Popsicle.instance<AuthService>();
auth.login();
4. Create a reactive state
final counter = ReactiveState<int>(0);
counter.listen((value) {
print("Counter updated: $value");
});
counter.value++; // Counter updated: 1
๐ฏ Lifecycle Management
Popsicle supports lifecycle-aware widgets and cleanup:
class MyState extends ReactiveState<int> with Disposable {
MyState() {
startTimer();
}
void startTimer() {
Timer.periodic(Duration(seconds: 1), (_) => value++);
}
@override
void dispose() {
print("Cleaning up MyState");
super.dispose();
}
}
๐งช Testing
final testContainer = DIContainer();
testContainer.registerSingleton<MockService>(MockService());
final service = testContainer.resolve<MockService>();
expect(service.doSomething(), true);
๐งฉ Extensions (Planned)
- โ Code generation for injectable services
- โ Integration with Riverpod, Bloc
- โ Dev tools inspector panel
- โ Web dashboard for live state inspection
๐ API Overview
Feature | Class/Method | Description |
---|---|---|
DI Registration | container.registerSingleton<T>() |
Register a singleton instance |
Lazy Singleton | container.registerFactory() |
Register a lazy-loaded singleton |
Reactive State | ReactiveState<T> |
State that emits changes |
Async State | AsyncState<T> |
Handle async loading / error / data |
Stream State | StreamState<T> |
Wrap a Dart stream as state |
Global Access | Popsicle.instance<T>() |
Access service globally, no context needed |
๐ก Why Popsicle?
- No black-box magic
- Minimal boilerplate
- Pure Dart core
- Flutter-ready but framework-agnostic
- Clean architecture friendly
๐ฅ Community
Coming soon: Discord + GitHub Discussions
๐ชช License
Apache License 2.0 ยฉ AR Rahman
This project is licensed under the Apache License 2.0.
๐ฌ Feedback
Have ideas or suggestions? Feel free to open an issue or pull request!