flutter_control 0.9.4

  • Readme
  • Changelog
  • Example
  • Installing
  • 78

Alpha version of Flutter Control

Stable but needs more testing and little care..


Flutter Control helps to separate Business Logic from UI and works based on BLoC and Provider patterns, but with little twist. Whole Logic is based in Controller or Model classes and Widgets are notified about changes via Streams.


Base classes

  • [BaseApp] Wraps MaterialApp and initializes Control and Factory. It's just shortcut to start with Flutter Control.
  • [AppControl] Is [InheritedWidget] around whole App. Holds Factory and other important Controllers.
  • [ControlFactory] Mainly initializes and stores Controllers, Models and other Logic classes. Also works as global Stream to provide communication and synchronization between separated parts of App.
  • [BaseLocalization] Json based localization, that supports simple strings, plurals and dynamic structures.
  • [RouteHandler] Initializes Widget and handles Navigation.

Streams

  • [ActionControl] Single or Broadcast Observable. Usable with [ControlBuilder] to dynamically build Widgets.
  • [FieldControl] Stream wrapper to use with [FieldStreamBuilder] or [FieldBuilder] to dynamically build Widgets.
  • [ListControl] Extended FieldControl to work with [List]
  • [RxControl] under construction..

Controllers

  • [BaseController] Stores all Business Logic and initializes self during Widget construction. Have native access to Factory and Control.
  • [StateController] Adds functionality to notify State of [ControlWidget].
  • [BaseModel] Lightweight version of Controller. Mainly used for Items in dynamic List or to separate/reuse Logic.
  • [InputController] Controller for [InputField] to control text, changes, validity, focus, etc. Controllers can be chained via 'next' and 'done' events.
  • [NavigatorController] Controller for [NavigatorStack.single] to control navigation inside Widget.
  • [NavigatorStackController] Controller for [NavigatorStack.pages] or [NavigatorStack.menu] to control navigation between Widgets.

Widgets

  • [ControlWidget] Base Widget to work with Controllers. Have native access to Factory and Control.

  • [BaseControlWidget] Widget with no init Controllers, but still have access to Factory etc. so Controllers can be get from there.

  • [SingleControlWidget] Widget with just one generic Controller.

  • [InputField] Wrapped [TextField] to provide more functionality and control via [InputController].

  • [FieldBuilder] Dynamic Widget builder controlled by [FieldControl].

  • [FieldBuilderGroup] Dynamic Widget builder controlled by multiple [FieldControl]s.

  • [ListBuilder] Wrapper of [FieldBuilder] to easily work with Lists.

  • [ControlBuilder] Dynamic Widget builder controlled by [ActionControl].

  • [StableWidget] Widget that is build just once.

  • [NavigatorStack.single] Enables navigation inside Widget.

  • [NavigatorStack.pages] Enables navigation between Widgets. Usable for menus, tabs, etc.

  • [NavigatorStack.menu] Same as 'pages', but Widgets are generated from [MenuItem] data.


Providers

  • [ControlProvider] Provides and initializes objects from [ControlFactory].
  • [BroadcastProvider] Globally broadcast events and data.
  • [PageRouteProvider] Specifies Route and WidgetBuilder settings for [RouteHandler].

Mixins

  • [LocalizationProvider] - mixin for any class, enables [BaseLocalization] for given object.

  • [RouteControl] - mixin for [ControlWidget], enables route navigation.

  • [RouteController] - mixin for [BaseController], enables route navigation bridge to [ControlWidget] with [RouteControl].

  • [TickerControl] - mixin for [ControlWidget], enables Ticker for given Widget.

  • [DisposeHandler] - mixin for any class, helps with object disposing.

  • [PrefsProvider] - mixin for any class, helps to store user preferences.


Helpers

  • [FutureBlock] Retriggerable delay.

  • [DelayBlock] Delay to wrap a block of code to prevent 'super fast' completion and UI jiggles.

  • [Parse] Helps to parse json primitives and Iterables. Provides default values if parsing fails.

  • [ArgProvider] Helps to retrieve object form List or Map.

  • [Device] Wrapper over [MediaQuery].

  • [WidgetInitializer] Helps to initialize Widgets with init data.

  • [BaseTheme] Some basic values to work with during Widget composition.

  • and more..


Example

Control and App initialization. TodoController is initialized and stored in global [ControlFactory].

   class MainApp extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return BaseApp(
         title: 'Flutter Control',
         theme: ThemeData(),
         entries: {
           'todo': TodoController(),
         },
         root: (context) => TodoPage(),
       );
     }
   }

Controller handles all Business Logic. Simply adds and removes items from List and recalculates item done count. [StringControl] and [ListControl] wraps [Stream] and notifies [FieldBuilder] about changes.

class TodoController extends BaseController {
  final doneCount = StringControl();
  final items = ListControl<TodoItemModel>();
  final input = InputController(regex: '.{3,}');

  TodoController() {
    items.subscribe((list) => _recalculateCount());
    input.done(addInputItem);
  }

  void addInputItem() {
    if (!input.validate()) {
      input.setError('invalid value');
      return;
    }

    items.add(TodoItemModel(this, input.value));

    input.setText(null);
  }

  void removeItem(TodoItemModel item) => items.remove(item);

  void _recalculateCount() => doneCount.setValue("${items.where((item) => item.done.isTrue).length}/${items.length}");

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

    items.clear(disposeItems: true);
    items.dispose();
  }
}

Model holds state of one item in list and notifies parent controller about changes.

class TodoItemModel extends BaseModel {
  final done = BoolControl();
  final String title;

  TodoItemModel(TodoController parent, this.title) {
    done.subscribe((value) => parent._recalculateCount());
  }

  @override
  void dispose() {
    done.dispose();
  }
}

List and Item builders. State management is handled by Controller and separate Widgets are build via [FieldBuilder]. Controller is automatically provided by [ControlFactory]. Controller can be provided manually or multiple controllers can be set to work with [ControlWidget].

class TodoPage extends SingleControlWidget<TodoController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TODO List'),
        actions: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16.0),
            child: Center(
              child: FieldBuilder<String>(
                controller: controller.doneCount,
                builder: (BuildContext context, String value) {
                  return Text(value);
                },
              ),
            ),
          ),
        ],
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: ListBuilder<TodoItemModel>(
              controller: controller.items,
              builder: (context, items) {
                return ListView.builder(
                  itemCount: items.length,
                  itemBuilder: (context, index) {
                    final item = items[index];
                    return FieldBuilder<bool>(
                      key: ObjectKey(item),
                      controller: item.done,
                      builder: (context, isDone) {
                        return FlatButton(
                          onPressed: item.done.toggle,
                          child: Row(
                            children: <Widget>[
                              Checkbox(
                                value: isDone,
                                onChanged: (checked) => item.done.setValue(checked),
                              ),
                              Text(
                                item.title,
                                style: isDone ? theme.textTheme.body1.copyWith(decoration: TextDecoration.lineThrough) : theme.textTheme.body1,
                              ),
                            ],
                          ),
                        );
                      },
                    );
                  },
                );
              },
            ),
          ),
          Container(
            color: theme.primaryColor,
            padding: const EdgeInsets.symmetric(horizontal: 16.0),
            child: Center(
              child: InputField(
                controller: controller.input,
                textInputAction: TextInputAction.next,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

[0.9.3] - RouteControl, NavigatorStack

[0.9.1] - Dependency update

[0.8.98] - Control Group Builders

[0.8.96] - Flutter 1.7 support

[0.8.5] - Alpha version


Base classes

  • [BaseApp] Wraps MaterialApp and initializes Control and Factory. It's just shortcut to start with Flutter Control.
  • [AppControl] Is [InheritedWidget] around whole App. Holds Factory and other important Controllers.
  • [ControlFactory] Mainly initializes and stores Controllers, Models and other Logic classes. Also works as global Stream to provide communication and synchronization between separated parts of App.
  • [BaseLocalization] Json based localization, that supports simple strings, plurals and dynamic structures.
  • [RouteHandler] Initializes Widget and handles Navigation.

Streams

  • [ActionControl] Single or Broadcast Observable. Usable with [ControlBuilder] to dynamically build Widgets.
  • [FieldControl] Stream wrapper to use with [FieldStreamBuilder] or [FieldBuilder] to dynamically build Widgets.
  • [ListControl] Extended FieldControl to work with [List]
  • [RxControl] under construction..

Controllers

  • [BaseController] Stores all Business Logic and initializes self during Widget construction. Have native access to Factory and Control.
  • [StateController] Adds functionality to notify State of [ControlWidget].
  • [BaseModel] Lightweight version of Controller. Mainly used for Items in dynamic List or to separate/reuse Logic.
  • [InputController] Controller for [InputField] to control text, changes, validity, focus, etc. Controllers can be chained via 'next' and 'done' events.
  • [NavigatorController] Controller for [NavigatorStack.single] to control navigation inside Widget.
  • [NavigatorStackController] Controller for [NavigatorStack.pages] or [NavigatorStack.menu] to control navigation between Widgets.

Widgets

  • [ControlWidget] Base Widget to work with Controllers. Have native access to Factory and Control.

  • [BaseControlWidget] Widget with no init Controllers, but still have access to Factory etc. so Controllers can be get from there.

  • [SingleControlWidget] Widget with just one generic Controller.

  • [InputField] Wrapped [TextField] to provide more functionality and control via [InputController].

  • [FieldBuilder] Dynamic Widget builder controlled by [FieldControl].

  • [FieldBuilderGroup] Dynamic Widget builder controlled by multiple [FieldControl]s.

  • [ListBuilder] Wrapper of [FieldBuilder] to easily work with Lists.

  • [ControlBuilder] Dynamic Widget builder controlled by [ActionControl].

  • [StableWidget] Widget that is build just once.

  • [NavigatorStack.single] Enables navigation inside Widget.

  • [NavigatorStack.pages] Enables navigation between Widgets. Usable for menus, tabs, etc.

  • [NavigatorStack.menu] Same as 'pages', but Widgets are generated from [MenuItem] data.


Providers

  • [ControlProvider] Provides and initializes objects from [ControlFactory].
  • [BroadcastProvider] Globally broadcast events and data.
  • [PageRouteProvider] Specifies Route and WidgetBuilder settings for [RouteHandler].

Mixins

  • [LocalizationProvider] - mixin for any class, enables [BaseLocalization] for given object.

  • [RouteControl] - mixin for [ControlWidget], enables route navigation.

  • [RouteController] - mixin for [BaseController], enables route navigation bridge to [ControlWidget] with [RouteControl].

  • [TickerControl] - mixin for [ControlWidget], enables Ticker for given Widget.

  • [DisposeHandler] - mixin for any class, helps with object disposing.

  • [PrefsProvider] - mixin for any class, helps to store user preferences.


Helpers

  • [FutureBlock] Retriggerable delay.

  • [DelayBlock] Delay to wrap a block of code to prevent 'super fast' completion and UI jiggles.

  • [Parse] Helps to parse json primitives and Iterables. Provides default values if parsing fails.

  • [ArgProvider] Helps to retrieve object form List or Map.

  • [Device] Wrapper over [MediaQuery].

  • [WidgetInitializer] Helps to initialize Widgets with init data.

  • [BaseTheme] Some basic values to work with during Widget composition.

  • and more..


example/README.md

BaseApp initializes Control and Factory. It's little shortcut to start with Flutter Control.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BaseApp(
      title: 'Flutter Control',
      theme: ThemeData(),
      entries: {
        'todo': MyController(),
      },
      root: (context) => MyWidget(),
    );
  }
}

Business logic layer.

class MyController extends BaseController {
  final count = FieldConrol<int>(0);

  void increment() => count.setValue(count.value++);

  void decrement() => count.setValue(count.value--);

  @override
  void dispose() {
    super.dispose();
    count.dispose();
  }
}

Presentation layer.

class MyWidget extends SingleControlWidget<MyController> {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        IconButton(
          icon: Icon(Icons.add),
          onPressed: controller.increment,
        ),
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          child: FieldBuilder<int>(
            controller: controller.count,
            builder: (context, value) => Text('$value'),
          ),
        ),
        IconButton(
          icon: Icon(Icons.remove),
          onPressed: controller.decrement,
        ),
      ],
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  flutter_control: ^0.9.4

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:flutter_control/core.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
58
Health:
Code health derived from static analysis. [more]
98
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
78
Learn more about scoring.

We analyzed this package on Nov 15, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.6.0
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.6

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Fix lib/src/widget/base_widget.dart. (-1.99 points)

Analysis of lib/src/widget/base_widget.dart reported 4 hints:

line 184 col 48: 'ArgHandler' is deprecated and shouldn't be used.

line 184 col 59: 'map' is deprecated and shouldn't be used.

line 305 col 20: 'ArgHandler' is deprecated and shouldn't be used.

line 305 col 31: 'map' is deprecated and shouldn't be used.

Format lib/core.dart.

Run flutter format to format lib/core.dart.

Format lib/src/app_base.dart.

Run flutter format to format lib/src/app_base.dart.

Fix additional 15 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/src/base_localization.dart (Run flutter format to format lib/src/base_localization.dart.)
  • lib/src/base_prefs.dart (Run flutter format to format lib/src/base_prefs.dart.)
  • lib/src/base_theme.dart (Run flutter format to format lib/src/base_theme.dart.)
  • lib/src/controller/base_controller.dart (Run flutter format to format lib/src/controller/base_controller.dart.)
  • lib/src/controller/field_control.dart (Run flutter format to format lib/src/controller/field_control.dart.)
  • lib/src/controller/route_control.dart (Run flutter format to format lib/src/controller/route_control.dart.)
  • lib/src/factory.dart (Run flutter format to format lib/src/factory.dart.)
  • lib/src/util/device.dart (Run flutter format to format lib/src/util/device.dart.)
  • lib/src/util/future_block.dart (Run flutter format to format lib/src/util/future_block.dart.)
  • lib/src/util/parser.dart (Run flutter format to format lib/src/util/parser.dart.)
  • lib/src/util/unit_id.dart (Run flutter format to format lib/src/util/unit_id.dart.)
  • lib/src/widget/input_field.dart (Run flutter format to format lib/src/widget/input_field.dart.)
  • lib/src/widget/navigation_stack.dart (Run flutter format to format lib/src/widget/navigation_stack.dart.)
  • lib/src/widget/stable_widget.dart (Run flutter format to format lib/src/widget/stable_widget.dart.)
  • lib/src/widget/widget_provider.dart (Run flutter format to format lib/src/widget/widget_provider.dart.)

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.4.0 <3.0.0
flutter 0.0.0
shared_preferences >=0.1.0 <1.0.0 0.5.4+5
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.7 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test