fmvvm 0.9.7

Flutter Android iOS web

An mvvm framework for Flutter. This is intended to easily create a formal application architecture.

example/lib/main.dart

import 'package:flutter/material.dart';

import 'package:fmvvm/bindings/bindings.dart';
import 'package:fmvvm/fmvvm.dart';
import 'package:fmvvm/interfaces/interfaces.dart';

void main() => runApp(MyApp());

class MyApp extends FmvvmApp {
  @override
  void registerComponents(ComponentResolver componentResolver) {
    componentResolver.registerType<_HomePageViewModel>(() {
      return _HomePageViewModel(
          componentResolver.resolveType<NavigationService>());
    });
    componentResolver.registerType<_CounterViewModel>(() {
      return _CounterViewModel(
          componentResolver.resolveType<NavigationService>());
    });
    componentResolver.registerType<_ListViewModel>(() {
      return _ListViewModel();
    });
  }

  @override
  String getInitialRoute() {
    return '_HomePageView';
  }

  @override
  String getTitle() {
    return 'fmvvm Demo';
  }

  @override
  Route getRoutes(RouteSettings settings) {
    if (settings.name == '_HomePageView') {
      var arguments = settings.arguments ??
          Core.componentResolver
              .resolveType<NavigationService>()
              .createViewModel<_HomePageViewModel>(null);
      return buildRoute(settings, new _HomePageView(arguments));
    } else if (settings.name == '_CounterView') {
      return buildRoute<int>(settings, new _CounterView(settings.arguments));
    } else if (settings.name == '_ListView') {
      return buildRoute(settings, new _RWListView(settings.arguments));
    }
    return null;
  }
}

class _HomePageView extends FmvvmStatefulWidget<_HomePageViewModel> {
  _HomePageView(ViewModel viewModel, {Key key, this.title})
      : super(viewModel, key: key);

  final String title;

  @override
  _HomePageViewState createState() => _HomePageViewState(bindableBase);
}

class _HomePageViewState extends FmvvmState<_HomePageView, _HomePageViewModel> {
  _HomePageViewState(_HomePageViewModel viewModel) : super(viewModel, true);

  TextEditingController controller;
  TextEditingController controller2;

  @override
  void initState() {
    super.initState();

    controller = TextEditingController();
    controller2 = TextEditingController();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            BindingWidget<_HomePageViewModel>(
              bindings: <Binding>[
                Binding(
                    'counter', bindableBase, _HomePageViewModel.counterProperty,
                    bindingDirection: BindingDirection.TwoWay,
                    valueConverter: _NumberValueConverter())
              ],
              builder: (bc) => Hero(
                    tag: 'countHero',
                    child: Text(BindingWidget.of<_HomePageViewModel>(bc)
                        .getValue('counter')),
                  ),
            ),
            BindingWidget<_HomePageViewModel>(
                bindings: <Binding>[
                  Binding('counter', bindableBase,
                      _HomePageViewModel.counterProperty,
                      bindingDirection: BindingDirection.TwoWay,
                      valueConverter: _NumberValueConverter())
                ],
                builder: (bc) {
                  controller.text = BindingWidget.of<_HomePageViewModel>(bc)
                      .getValue('counter');
                  controller.selection = new TextSelection.collapsed(
                      offset: controller.text.length);
                  return TextField(
                    style: Theme.of(context).textTheme.display1,
                    controller: controller,
                    onChanged: BindingWidget.of<_HomePageViewModel>(bc)
                        .getOnChanged('counter'),
                  );
                }),
            BindingWidget<_HomePageViewModel>(
                bindings: <Binding>[
                  Binding('counter', bindableBase,
                      _HomePageViewModel.counterProperty,
                      bindingDirection: BindingDirection.TwoWay,
                      valueConverter: _NumberValueConverter())
                ],
                builder: (bc) {
                  var controllerText = BindingWidget.of<_HomePageViewModel>(bc)
                      .getValue('counter') as String;
                  controller2.text = controllerText;
                  controller2.selection = new TextSelection.collapsed(
                      offset: controllerText.length);
                  return TextField(
                    style: Theme.of(context).textTheme.display1,
                    controller: controller2,
                    onChanged: BindingWidget.of<_HomePageViewModel>(bc)
                        .getOnChanged('counter'),
                  );
                }),
            BindingWidget<_HomePageViewModel>(
              bindings: <Binding>[
                Binding('testBool', bindableBase,
                    _HomePageViewModel.testBoolProperty,
                    bindingDirection: BindingDirection.TwoWay)
              ],
              builder: (c) => Switch(
                    value: BindingWidget.of<_HomePageViewModel>(c)
                        .getValue('testBool') as bool,
                    onChanged: BindingWidget.of<_HomePageViewModel>(c)
                        .getOnChanged('testBool'),
                  ),
            ),
            BindingWidget<_HomePageViewModel>(
              bindings: <Binding>[
                Binding('testBool', bindableBase,
                    _HomePageViewModel.testBoolProperty,
                    bindingDirection: BindingDirection.TwoWay)
              ],
              builder: (c) => Expanded(
                    child: Switch(
                      value: BindingWidget.of<_HomePageViewModel>(c)
                          .getValue('testBool') as bool,
                      onChanged: BindingWidget.of<_HomePageViewModel>(c)
                          .getOnChanged('testBool'),
                    ),
                  ),
            ),
            FlatButton(
                child: Text(
                  'Go to Count and add 1',
                ),
                onPressed: () {
                  bindableBase.viewValueAddOne.execute();
                }),
            FlatButton(
                child: Text(
                  'Go to Read/Write List',
                ),
                onPressed: () {
                  bindableBase.goToRWList.execute();
                }),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: bindableBase.incrementCounter.execute,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class _CounterView extends FmvvmStatelessWidget<_CounterViewModel> {
  _CounterView(_CounterViewModel viewModel, {Key key})
      : super(viewModel, true, key: key);

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
        appBar: AppBar(
          title: Text('Current Count'),
        ),
        body: WillPopScope(
            onWillPop: () async {
              await bindableBase.navigateBack.execute();
              return false;
            },
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'Counter Value:',
                  ),
                  BindingWidget<_CounterViewModel>(
                    bindings: <Binding>[
                      Binding('counter', bindableBase,
                          _CounterViewModel.counterProperty,
                          valueConverter: _NumberValueConverter())
                    ],
                    builder: (bc) => Hero(
                          tag: 'countHero',
                          child: Text(BindingWidget.of<_CounterViewModel>(bc)
                              .getValue('counter')),
                        ),
                  ),
                ],
              ),
            )));
  }
}

class _RWListView extends FmvvmStatefulWidget<_ListViewModel> {
  _RWListView(ViewModel viewModel, {Key key, this.title})
      : super(viewModel, key: key);

  final String title;

  @override
  _RWListState createState() => _RWListState(bindableBase);
}

class _RWListState extends FmvvmState<_RWListView, _ListViewModel> {
  _RWListState(_ListViewModel viewModel) : super(viewModel, true);

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('RW List'),
      ),
      body: BindingWidget<_ListViewModel>(
        bindings: <Binding>[
          Binding('list', bindableBase, _ListViewModel.myListProperty)
        ],
        builder: (bc) => ListView.builder(
              shrinkWrap: true,
              padding: const EdgeInsets.all(20.0),
              itemCount: (BindingWidget.of<_ListViewModel>(bc).getValue('list')
                      as NotificationList)
                  .length,
              itemBuilder: (context, position) {
                return _ListRowWidget((BindingWidget.of<_ListViewModel>(bc)
                    .getValue('list') as NotificationList)[position]);
              },
            ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => bindableBase.addRow.execute(),
        child: Icon(Icons.add),
      ),
    );
  }
}

class _ListRowWidget extends FmvvmStatelessWidget<_ListItem> {
  _ListRowWidget(_ListItem bindableBase) : super(bindableBase, false);

  @override
  Widget build(BuildContext context) {
    super.build(context);

    return ListTile(
        title: Text(bindableBase.lineOne),
        subtitle: Text(bindableBase.lineTwo));
  }
}

class _HomePageViewModel extends ViewModel {
  _HomePageViewModel(this._navigationService);

  final NavigationService _navigationService;

  static PropertyInfo counterProperty = PropertyInfo('counter', int);

  int get counter => getValue(counterProperty);
  set counter(int value) => setValue(counterProperty, value);

  static PropertyInfo currentDateProperty = PropertyInfo('currentDate', int);

  DateTime get currentDate => getValue(currentDateProperty);
  set currentDate(DateTime value) => setValue(currentDateProperty, value);

  static PropertyInfo testBoolProperty = PropertyInfo('testBool', bool, false);

  bool get testBool => getValue(testBoolProperty);
  set testBool(bool value) => setValue(testBoolProperty, value);

  Command _incrementCounter;

  Command get incrementCounter {
    _incrementCounter ??= Command(() {
      counter++;
    });
    return _incrementCounter;
  }

  Command _navigate;

  Command get viewValueAddOne {
    _navigate ??= Command(() async {
      counter = await _navigationService
          .navigateForResult<int, _CounterViewModel>(parameter: counter);
    });
    return _navigate;
  }

  Command _goToRWList;

  Command get goToRWList {
    _goToRWList ??= Command(() {
      _navigationService.navigate<_ListViewModel>();
    });
    return _goToRWList;
  }
}

class _CounterViewModel extends ViewModel {
  _CounterViewModel(this._navigationService);

  final NavigationService _navigationService;

  @override
  void init(Object parameter) {
    setValue(counterProperty, parameter);
  }

  static PropertyInfo counterProperty = PropertyInfo('counter', int);
  int get counter => getValue(counterProperty);

  Command _navigateBack;

  Command get navigateBack {
    _navigateBack ??= Command(() {
      _navigationService.navigateBackWithResult(counter + 1);
    });
    return _navigateBack;
  }
}

class _ListViewModel extends ViewModel {
  _ListViewModel() {
    myList = NotificationList();
    myList.add(_ListItem("First", "Item"));
    myList.add(_ListItem("Second", "Item"));
  }
  static PropertyInfo myListProperty = PropertyInfo('myList', NotificationList);

  NotificationList<_ListItem> get myList => getValue(myListProperty);
  set myList(NotificationList<_ListItem> value) =>
      setValue(myListProperty, value);

  Command _addRow;

  Command get addRow {
    _addRow ??= Command(() {
      myList.add(_ListItem("Another", "Item"));
    });
    return _addRow;
  }
}

class _ListItem extends BindableBase {
  _ListItem(String lineOne, String lineTwo) {
    this.lineOne = lineOne;
    this.lineTwo = lineTwo;
  }
  static PropertyInfo lineOneProperty = PropertyInfo('lineOne', String);

  String get lineOne => getValue(lineOneProperty);
  set lineOne(String value) => setValue(lineOneProperty, value);

  static PropertyInfo lineTwoProperty = PropertyInfo('lineTwo', String);

  String get lineTwo => getValue(lineTwoProperty);
  set lineTwo(String value) => setValue(lineTwoProperty, value);
}

class _NumberValueConverter implements ValueConverter {
  Object convert(Object source, Object value, {Object parameter}) {
    return value.toString();
  }

  Object convertBack(Object source, Object value, {Object parameter}) {
    return int.tryParse(value) ?? 0;
  }
}
1
likes
100
pub points
80%
popularity

An mvvm framework for Flutter. This is intended to easily create a formal application architecture.

Repository (GitHub)
View/report issues

Documentation

API reference

Uploader

7491420@gmail.com

License

MIT (LICENSE)

Dependencies

flutter

More

Packages that depend on fmvvm