GithubHelp home page GithubHelp logo

surfstudio / mwwm Goto Github PK

View Code? Open in Web Editor NEW
38.0 27.0 1.0 490 KB

Architecture for Flutter apps by Surf

License: Apache License 2.0

Objective-C 0.04% Dart 94.85% Kotlin 0.14% Ruby 3.37% Swift 0.42% HTML 1.18%

mwwm's Introduction

SurfGear

pub package

Software architectural pattern for Flutter apps.

Description

MWWM is based on principles of Clean Architecture and is a variation of MVVM.

It consists of three parts: Widget, WidgetModel and Model.

Widget — a representation layer that contains only UI related code.

WidgetModel - handles and accumulates all data needed for Widget: objects of the domain layer, scroll position, text fields values, animation state, etc. WidgetModel uses Model for interaction with various data sources.

Model - a link between WidgetModel and "the external world": data sources, services or other abstraction layers. It allows to develop both separately and have a possibility to modify one layer with no need for changing the other. Model is represented by two components: Change (a signal to model which means what we want to achieve) and Performer (that knows how to achieve it).

Why?

This architecture completely separates design and logic. Adds the ability to work on independent layers by different developers. Adds autonomy to work, like HTML and CSS.

How to use

Create a WidgetModel class by extending [WidgetModel].

class RepositorySearchWm extends WidgetModel {

  RepositorySearchWm(
    WidgetModelDependencies baseDependencies, //1
    Model model, //2
    ) : super(baseDependencies, model: model); //3

}

1 - WidgetModelDependencies is a bundle of required dependencies. Default there is ErrorHandler, which give possibility to place error handling logic in one place. You must provide an implementation of handler.

2 - Model is contract with service layer. For now, it is optional feature. It is possible to use services directly but not recommended.

3 - don't forgive about provide model to superclass if you wont to use Model.

Add Widget simply by creating StatefulWidget and replace parent class with CoreMwwmWidget

class RepositorySearchScreen extends CoreMwwmWidget {

  //...

  @override
  State<StatefulWidget> createState() {
    return _RepositorySearchScreenState();
  }
}

By convention create a same constructor:

  RepositorySearchScreen({
    WidgetModelBuilder wmBuilder, // need to testing
  }) : super(
          widgetModelBuilder: wmBuilder ??
              (ctx) => RepositorySearchWm(
                    // provide args,
                  ),
        );

or by route:

  class RepositorySearchRoute extends MaterialPageRoute {
    RepositorySearchRoute()
        : super(
            builder: (context) => RepositorySearchScreen(
              widgetModelBuilder: _buildWm,
            ),
          );
  }

  WidgetModel _buildWm(BuildContext context) => RepositorySearchWm(
        context.read<WidgetModelDependencies>(),
        Model([
          // performets
        ]),
      );

Change parent of State of StatefulWidget to WidgetState:

class _RepositorySearchScreenState extends WidgetState<RepositorySearchWm>

All done! You create your presentation.

FAQ

Where can I place UI?

Simply in build method in WidgetState. No difference with Flutter framework.

How can I obtain a WM?

WidgetState has WidgetModel after initState() called. There is a getter - wm - to get your WidgetModel in your Widget.

Where should I place navigation logic?

Only in WidgetModel. But we don't hardcodea way to do this, yet.

Sercice(bussines) Layer

It is optional paragraph. You can write connection with services your favorite way.

To work with business logic need to decribe a contract which consists of two parts: Change and Performer.

Change - is an intention to do something on service layer. Change can has data. Formally, it is an arguments of some function.

Performer<R, Change> - is a functional part of this contract. It is so close to UseCase. Performer, in ideal world, do only one thing. It is small part og logic which needed to perform Change.

Recommended file structure

We recomend following structure:

  • ./
    • data/
    • model/
      • services(repository)/
      • changes.dart // can split
      • performer.dart // can split
    • ui/
      • screen(widget)/
        • wm.dart
        • route.dart
        • screen(widget).dart

Feature RoadMap

  • Coordinator - abstraction to place navigation logic
  • Code generation (may be)
  • Somthing else ? Create an issue with request to feature.

mwwm's People

Contributors

mbixjkee avatar saturov avatar trushchinskii avatar trushchinskii-surf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

evoswork

mwwm's Issues

Как взаимодействовать со Stateful виджетами из WidgetModel

Добрый день!

В примере я видел, что вы допускаете передачу стейта виджета в конструктор WidgetModel (например NavigatorState). Но как быть со stateful виджетами созданными внутри WidgetState, например виджет Form? На момент создания WidgetModel метод build еще не отработал, в лучшем случае мы можем передать в WidgetState тот же GlobalKey, с которым потом создадим Form.

Пример иерархии:

class SomeScreen extends CoreMwwmWidget {
   ...
}

class SomeScreenState extends WidgetState<SomeScreenWm> {
    Widget build(BuildContext context) {
        return Form(
                ...
                Button(onTap: () => wm.submit()),
        );
    }
}

class SomeScreenWm extends WidgetModel {
    void submit() {
        if(form.validate()) {
        ....
        } else {
        }
  
    }
}

Я думаю такая проблема присуща любому виджету, который допускает императивное взаимодействие со своим состоянием.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.