built_viewmodel_generator 1.2.6 copy "built_viewmodel_generator: ^1.2.6" to clipboard
built_viewmodel_generator: ^1.2.6 copied to clipboard

discontinued

built_viewmodel_generator to generate ViewModel(s). This library is the dev dependency.

Deprecated #

This library is deprecated from now and will not be supported anymore. Please use the BLoC pattern (Build reactive mobile apps with Flutter (Google I/O '18)) instead, which does (more or less) the same but (for now) without code generation.

built_viewmodel.dart #

The built_viewmodel.dart package provides a way to create ViewModel classes. It is a little bit inspired by the Android ViewModel but just a little bit ;-)

Usually, you call setState() whenever the state of the Widget should change. But in my opinion, it is not a good idea to call setState() when just a small part of the whole state has changed (read more: How fast is Flutter? I built a stopwatch app to find out., Avoiding Empty State Callbacks).

This package creates lots of Streams (as much as you need) to feed StreamBuilders.

Let's start #

Create an abstract class, e.g. MyHomePageViewModel:

library main;

import 'dart:async';

import 'package:built_viewmodel/built_viewmodel.dart';

part 'main.g.dart';

abstract class MyHomePageViewModel implements ViewModel<MyHomePageViewModelController> {


  factory MyHomePageViewModel() = _$MyHomePageViewModel;
  MyHomePageViewModel._();
}

And add a reference of it to the Widget:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final MyHomePageViewModel model = new MyHomePageViewModel();
  final String title;

  @override
  _MyHomePageState createState() {
    model.setCounter(0);
    return new _MyHomePageState();
  }
}

For now, the ViewModel makes nothing. You have to add your needed stream(s):

abstract class MyHomePageViewModel implements ViewModel<MyHomePageViewModelController> {

  Stream<int> get counter;   // new

  factory MyHomePageViewModel() = _$MyHomePageViewModel;
  MyHomePageViewModel._();

You also need to add a code generator. Create a tool/build.dart file with the following content:

import 'dart:async';

import 'package:build_config/build_config.dart';
import 'package:build_runner/build_runner.dart';
import 'package:built_viewmodel_generator/built_viewmodel_generator.dart';
import 'package:source_gen/source_gen.dart';

final builders = [
  applyToRoot(
    new PartBuilder([
      new BuiltViewModelGenerator(),
    ]),
    generateFor: const InputSet(
      include: const [
        'lib/*.dart',
      ],
    ),
  ),
];

Future main(List<String> args) async {
  await build(
    builders,
    deleteFilesByDefault: true,
    verbose: false,
  );
}

Execute the tool/build.dart file and it will generate a main.g.dart file which has all the logic for your stream(s).

Use the stream #

To use the stream(s) you need a StreamBuilder where you have to set the stream to the one from the ViewModel:

new StreamBuilder(
  stream: widget.model.counter,
  builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
    if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
    switch (snapshot.connectionState) {
      case ConnectionState.none:
        return new Text('not connected');
      case ConnectionState.waiting:
        return new Text('awaiting interaction...');
      case ConnectionState.active:
        return new Text('counter: ${snapshot.data}');
      case ConnectionState.done:
        return new Text('counter: ${snapshot.data} (closed)');
      default:
        throw "Unknown: ${snapshot.connectionState}";
    }
  },
),

Whenever you send a new value to the stream the content of the StreamBuilder will change but only this small part and not the whole state.

To do that add a void setCounter(int value) method to the ViewModel ...

abstract class MyHomePageViewModel implements ViewModel<MyHomePageViewModelController> {
  Stream<int> get counter;

  void setCounter(int value) => controller.counter.add(value);   // new

  factory MyHomePageViewModel() = _$MyHomePageViewModel;
  MyHomePageViewModel._();
}

... and just call it.

Don't forget ... #

... to call dispose()

Add this to your State class

@override
void dispose() {
  widget.model.dispose();
  super.dispose();
}

Advanced feature #

Sometimes you need to know the state of the stream, for example, to start a download.

You can create methods and annotate them with one of this annotations: @OnListenHandler, @OnPauseHandler, @OnResumeHandler, @OnCancelHandler. These annotations have a name parameter which must match with the name of the stream.

For example, if you have a counter stream Stream<int> get counter, and you want to know when something is listening for it the annotation should look like this: @OnListenHandler('counter').

abstract class MyHomePageViewModel implements ViewModel<MyHomePageViewModelController> {
  Stream<int> get counter;

  @OnListenHandler('counter')                           // new
  onListen() => print('start listening for updates');   // new

  void setCounter(int value) => controller.counter.add(value);

  factory MyHomePageViewModel() = _$MyHomePageViewModel;

  MyHomePageViewModel._();
}

You can find the full example here.

0
likes
0
pub points
0%
popularity

Publisher

unverified uploader

built_viewmodel_generator to generate ViewModel(s). This library is the dev dependency.

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

analyzer, build, build_config, code_builder, dart_style, quiver, source_gen

More

Packages that depend on built_viewmodel_generator