Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/xamantra/momentum

MVC pattern for flutter. Works as state management, dependency injection and service locator.
https://github.com/xamantra/momentum

dependency-injection flexible flutter momentum mvc mvc-architecture mvc-pattern package state-management

Last synced: 3 months ago
JSON representation

MVC pattern for flutter. Works as state management, dependency injection and service locator.

Lists

README

        




MVC pattern for flutter. Works as state management, dependency injection and service locator.


Pub Version
Test

GitHub stars
GitHub license
GitHub last commit

---

Model View Controller



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.

# Example
If you want to see a full code example that runs. Visit the [example](https://pub.dev/packages/momentum/example) tab for more details or you can visit the [official webpage](https://www.xamantra.dev/momentum/#/). Otherwise, if you only want to see a glimpse of how momentum works, read the [Overview](#overview) and [FAQs](#faqs) below.

**Advance Example:** [Listify](https://github.com/xamantra/listify) (clone the repo and run the app, requires Flutter 2.0.0)

# Overview
**MomentumModel** - the data or state. Must be *Immutable*.
```dart
class ProfileModel extends MomentumModel {
// ...

final int userId;
final String username;

// ...
}
```

**MomentumBuilder** - the view or widget to display the state.
```dart
MomentumBuilder(
controllers: [ProfileController], /// injects both `ProfileController` and `ProfileModel`.
builder: (context, snapshot) {
var profileState = snapshot(); /// grab the `ProfileModel` using snapshot.
var username = profileState.username;
return // some widgets here ...
}
)
```

**MomentumController** - the logic to manipulate the model or state.
```dart
class ProfileController extends MomentumController {
// ...

Future loadProfile() async {
var profile = await http.get(...);
// update the model's properties.
model.update(
userId: profile.userId,
username: profile.username,
);
}

// ...
}
```

# FAQs
## How to *rebuild* the widget?
Calling `model.update(...)` from inside the controller rebuilds all the `MomentumBuilder`s that are listening to it.


## How to access the *model* object?
It is automatically provided by `MomentumController` for you to use. Inside a controller class, you can access it directly. It's never null.


## How to *initialize* the model or state?
By implementing the `T init()` method which is required by *MomentumController*. Like this:
```dart
class ShopController extends MomentumController {

@override
ShopModel init() {
return ShopModel(
this, // required
shopList: [],
productList: [],
);
}
}
```


## Can I access the model properties inside my controller?
Of course. The **model** object is already provided by *MomentumController* meaning you can also directly access its properties like this:
```dart
class ShopController extends MomentumController {

bool hasProducts() {
return model.productList.isNotEmpty;
}
}
```


## Is there a special *setup* required for Momentum to run?
Yes, definitely. This is the required setup for *Momentum* in a flutter app:
```dart
void main() {
runApp(momentum());
}

Momentum momentum() {
return Momentum(
child: MyApp(),
controllers: [
ProfileController(),
ShopController(),
],
// and more optional parameters here.
);
}
```

# Testing
Momentum is highly testable. This is how a basic **widget testing** for momentum would look like:
```dart
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:
```dart
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
});
}
```

# Other optional features
- **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*.

## Router issues
- 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 `RouterPage` widget 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.

# API Reference
Visit the [official webpage](https://www.xamantra.dev/momentum/#/) 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](https://github.com/xamantra/momentum/issues). I always check them everyday.