A super powerful flutter state management library inspired with MVC pattern
momentum
A super powerful flutter state management library inspired with MVC pattern with a very flexible dependency injection.
Features
- Very flexible
Dependency Injection
to easily instantiate any dependencies once and reuse multiple times across the app. Persistence
support for states and routing. Use any storage provider.- Time travel (
undo/redo
) support in one line of code out of the box. - Optional
Equatable
support. (Improves time travel). Immutable
states/models. There's only one way to rebuild a widget.- You can
reset a state
or all of the states. Skip rebuilds
. Widget specific.- Easy to use
Event System
for sending events to the widgets. For showing dialogs/snackbars/alerts/navigation/etc. - Momentum doesn't have any dependencies so it increases compatibility in other platforms.
- Supports older versions of flutter.
Core Concepts
- Momentum only uses
setState(...)
under the hood. - The method
model.update(...)
is the setState of momentum. - Modular project structure because of the component system (
MomentumController
+MomentumModel
). - Everything can be reusable from widgets, services, data, state to logic.
- Everything is in the widget tree.
Preview
In this image the process was like this:
- Open the app (Home Page).
- Go to Add New List page.
- Input some data.
- Close and Terminate on task view.
- Reopen the app again.
And magic happens! All the inputs were retained and not just that but also including the page where you left off. Navigation history is also persisted which means pressing the system back button will navigate you to the correct previous page.
Dark Mode
This theming is done manually using momentum.
Source Code for this Example App
This example app shows how powerful momentum is.
Quick Start
You only have to install one package and momentum doesn't have any peer dependencies.
Create
To get started, flutter create
an app. Name it however you want.
Installing
-
Add this to your package's
pubspec.yaml
file:dependencies: momentum: ^1.1.6
It is not recommended to use the one from GitHub because the changes there are subject to breaking changes on future pushes to the repository.
-
You can install this package from the command-line:
flutter pub get
Alternatively, your editor might support
flutter pub get
. -
Now in your Dart code, you can use:
import 'package:momentum/momentum.dart';
You only have to import this one file alone and you'll be able to use all momentum API.
Counter App Example
Copy this example counter app code and run it:
import 'package:flutter/material.dart';
import 'package:momentum/momentum.dart';
void main() {
runApp(
Momentum(
controllers: [CounterController()],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Momentum State Management',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomeWidget(),
);
}
}
class CounterController extends MomentumController<CounterModel> {
@override
CounterModel init() {
return CounterModel(
this,
value: 0,
);
}
void increment() {
var value = model.value; // grab the current value
model.update(value: value + 1); // update state (rebuild widgets)
print(model.value); // new or updated value
}
}
class CounterModel extends MomentumModel<CounterController> {
CounterModel(
CounterController controller, {
this.value,
}) : super(controller);
final int value;
@override
void update({
int value,
}) {
CounterModel(
controller,
value: value ?? this.value,
).updateMomentum();
}
}
class HomeWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Momentum Counter'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
MomentumBuilder(
controllers: [CounterController],
builder: (context, snapshot) {
var counter = snapshot<CounterModel>();
return Text(
'${counter.value}',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: MomentumBuilder(
controllers: [CounterController],
// we don't need to rebuild the increment button.
dontRebuildIf: (_, __) => true,
builder: (context, snapshot) {
var controller = snapshot<CounterModel>().controller;
return FloatingActionButton(
onPressed: controller.increment,
tooltip: 'Increment',
child: Icon(Icons.add),
);
},
),
);
}
}
- Inside
main()
methodMomentum
is set as the root widget of the app. - The
CounterController
is instantiated incontrollers
parameter. - Inside the
CounterController
there is anincrement()
method that updates the value. It calls the methodmodel.update(...)
which will rebuild the widget. - The
CounterModel
is where the props are defined and currently has thevalue
property. - The
HomeWidget
usesMomentumBuilder
which is used for displaying the model properties to the screen. You can callmodel.update(...)
to rebuild this widget.