搜尋套件、儲存庫與 APP 分類

GitHub 儲存庫xamantra/momentum

momentum

Flutter 的 MVC 模式。用作狀態管理、依賴注入和服務定位器。

momentum 專案封面
星標
119
分支
17
最近推送(UTC)
2021年10月15日
專案狀態
未封存

原始 README

以下為英文專案原文快照,最新內容請造訪 GitHub。

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 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)

Overview

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,
    );
  }

  // ...
}

FAQs

How to rebuild the widget?

Calling model.update(...) from inside the controller rebuilds all the MomentumBuilders 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:

class ShopController extends MomentumController<ShopModel> {

  @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:

class ShopController extends MomentumController<ShopModel> {

  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:

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:

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
  });
}

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 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.

xamantra GitHub avatar
GitHub 作者

xamantra ↗

flutter dev

xamantraPhilippines官方網站 ↗
語言Dart

分類

此儲存庫發佈的套件

使用的依賴

依賴清單 6 項

如何選擇適合專案的儲存庫?

先依使用情境篩選,再比較專案活躍情況,最後到原始儲存庫確認使用要求。

  1. 透過儲存庫名稱、作者或描述搜尋,再依技術分類縮小範圍。
  2. 綜合星標、分支與最近推送比較專案;星標反映社群關注,不保證品質。
  3. 使用前在 GitHub 確認 README、授權條款與 Issues。

來源與維護

“A repository is the most basic element of GitHub.”

GitHub Docs — About repositories ↗