MVC pattern for flutter. Works as state management, dependency injection and service locator.
Here's a diagram describing the flow between the state (model), widget (view) and the logic (controller):
Both MomentumController and MomentumModel are abstract classes that needs to be implemented. A pair of model and controller is called a component. MomentumBuilder is simply a widget. This is used to listen to controllers for rebuilds and accessing models to display their values.
If you want to see a full code example that runs. Visit the example tab for more details or you can visit the official webpage. Otherwise, if you only want to see a glimpse of how momentum works, read the Overview and FAQs below.
Advance Example: Listify (clone the repo and run the app, requires Flutter 2.0.0)
MomentumModel - the data or state. Must be Immutable.
class ProfileModel extends MomentumModel<ProfileController> {
  // ...
  final int userId;
  final String username;
  // ...
}MomentumBuilder - the view or widget to display the state.
MomentumBuilder(
  controllers: [ProfileController], /// injects both `ProfileController` and `ProfileModel`.
  builder: (context, snapshot) {
    var profileState = snapshot<ProfileModel>(); /// grab the `ProfileModel` using snapshot.
    var username = profileState.username;
    return // some widgets here ...
  }
)MomentumController - the logic to manipulate the model or state.
class ProfileController extends MomentumController<ProfileModel> {
  // ...
  Future<void> loadProfile() async {
    var profile = await http.get(...);
    // update the model's properties.
    model.update(
      userId: profile.userId,
      username: profile.username,
    );
  }
  // ...
}Calling model.update(...) from inside the controller rebuilds all the MomentumBuilders that are listening to it.
It is automatically provided by MomentumController for you to use. Inside a controller class, you can access it directly. It's never null.
By implementing the T init() method which is required by MomentumController. Like this:
class ShopController extends MomentumController<ShopModel> {
  @override
  ShopModel init() {
    return ShopModel(
      this, // required
      shopList: [],
      productList: [],
    );
  }
}Of course. The model object is already provided by MomentumController meaning you can also directly access its properties like this:
class ShopController extends MomentumController<ShopModel> {
  bool hasProducts() {
    return model.productList.isNotEmpty;
  }
}Yes, definitely. This is the required setup for Momentum in a flutter app:
void main() {
  runApp(momentum());
}
Momentum momentum() {
  return Momentum(
    child: MyApp(),
    controllers: [
      ProfileController(),
      ShopController(),
    ],
    // and more optional parameters here.
  );
}Momentum is highly testable. This is how a basic widget testing for momentum would look like:
void main() {
  testWidgets('should display username', (tester) async {
    var profileCtrl = ProfileController();
    await tester.pumpWidget(
      Momentum(
        child: MyApp(),
        controllers: [profileCtrl],
      ),
    );
    await tester.pumpAndSettle();
    profileCtrl.updateUsername("johndoe");
    await tester.pumpAndSettle(); // ensure rebuilds
    expect(profileCtrl.model.username, "johndoe"); // unit check
    expect(find.text("johndoe"), findsOneWidget); // widget check
  });
}Or you might not be a fan of widget testing and only want to test your components:
void main() {
  test('should display username', () async {
    var profileCtrl = ProfileController();
    var tester = MomentumTester(
      Momentum(
        controllers: [profileCtrl],
      ),
    );
    await tester.init();
    profileCtrl.updateUsername("johndoe");
    expect(profileCtrl.model.username, "johndoe"); // unit check
  });
}- Routing - Navigation system that supports persistence. The app will open the page where the user left off.
- Event System - For showing dialogs, prompts, navigation, alerts.
- Persistence State - Restore state when the app opens again.
- Testing - Tests your widgets and logic. Built-in helper class for unit testing.
Momentum leverages the power of setState(..) and StatefulWidget behind the scenes. The feature Event System uses Stream.
- The router doesn't support named routes yet.
- The parameter handling for router is slightly verbose. And might be complicated for some. But it works magically.
- Needs to explicitly implement RouterPagewidget in order to handle the system's back button.
- (FIXED ✅) The router breaks after hot reload. Only a problem during development but it should work in normal execution.
Visit the official webpage of momentum to browse the full api reference, guides, and examples.
Thanks for checking out momentum. I hope you try it soon and don't hesitate to file on issue on github. I always check them everyday.

