diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3ffff6e --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ + +build/ +ios/.generated/ +ios/Flutter/Generated.xcconfig +ios/Runner/GeneratedPluginRegistrant.* + +# Remove the following pattern if you wish to check in your lock file +pubspec.lock + +# Directory created by dartdoc +doc/api/ + +.idea/ + +android/local.properties +dependencies_flutter.iml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..043969c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +## 0.0.1 + +- Initial version. + +## 0.0.2 + +- Added example. + +## 0.0.3 + +- Remove `dependencies` export. + +## 0.0.4 + +- Added `InjectorWidgetMixin`. + +## 0.0.5 + +- Added `BindingInjectorWidget`. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a128036 --- /dev/null +++ b/LICENSE @@ -0,0 +1,229 @@ +Copyright 2017, the Flutter project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2011 - 2013 Paul Burke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6aa0fd9 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +[![pub package](https://img.shields.io/pub/v/dependencies_flutter.svg)](https://pub.dartlang.org/packages/dependencies_flutter) + + +Simple package ease the use of the [dependencies](https://pub.dartlang.org/packages/dependencies) with Flutter +leveraging the power of `InheritedWidget`. + +## Usage + +```dart +class SomeRootWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return InjectorWidget.bind( + binderFunc: (binder) { + binder + ..install(MyModule()) + ..bindSingleton("api123", name: "api_key"); + }, + child: SomeWidget() + ); + } +} +``` + +You can also extend `BindingInjectorWidget` to configure your dependencies: + +```dart +class MyBinder extends BindingInjectorWidget { + MyBinder({Key key, @required Widget child}): super(key: key, child: child); + @override + void configure(Binder binder) { + binder + ..bindSingleton(Object()); + } +} +``` + +You can later refer to the injector like any other `InheritedWidget`. + +```dart +class SomeWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + final injector = InjectorWidget.of(context); + final apiKey = injector.get(name: "api_key"); + return SomeContainerNeedingTheKey(apiKey); + } +} +``` + +Or using the `InjectorWidgetMixin`: + +```dart +class SomeWidget extends StatelessWidget with InjectorWidgetMixin { + @override + Widget buildWithInjector(BuildContext context, Injector injector) { + final object = injector.get(); + print(object); + return Container(); + } +} +``` \ No newline at end of file diff --git a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 0000000..d007606 --- /dev/null +++ b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,23 @@ +package io.flutter.plugins; + +import io.flutter.plugin.common.PluginRegistry; + +/** + * Generated file. Do not edit. + */ +public final class GeneratedPluginRegistrant { + public static void registerWith(PluginRegistry registry) { + if (alreadyRegisteredWith(registry)) { + return; + } + } + + private static boolean alreadyRegisteredWith(PluginRegistry registry) { + final String key = GeneratedPluginRegistrant.class.getCanonicalName(); + if (registry.hasPlugin(key)) { + return true; + } + registry.registrarFor(key); + return false; + } +} diff --git a/example/example.dart b/example/example.dart new file mode 100644 index 0000000..55b6119 --- /dev/null +++ b/example/example.dart @@ -0,0 +1,67 @@ +import 'package:dependencies_flutter/dependencies_flutter.dart'; +import 'package:flutter/material.dart'; +import 'package:dependencies/dependencies.dart'; + +class SomeRootWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return InjectorWidget.bind( + binderFunc: (binder) { + binder + ..install(MyModule()) + ..bindSingleton("api123", name: "api_key"); + }, + child: Container( + child: Container( + child: SomeWidget(), + ) + ) + ); + } +} + +class MyModule extends Module { + @override + void configure(Binder binder) { + binder + ..bindSingleton(Object()); + } +} + +class SomeWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + final injector = InjectorWidget.of(context); + final apiKey = injector.get(name: "api_key"); + print(apiKey); + return Container(); + } +} + +class SomeOtherWidget extends StatelessWidget with InjectorWidgetMixin { + @override + Widget buildWithInjector(BuildContext context, Injector injector) { + final object = injector.get(); + print(object); + return Container(); + } +} + +class MyBinder extends BindingInjectorWidget { + MyBinder({Key key, @required Widget child}): super(key: key, child: child); + @override + void configure(Binder binder) { + binder + ..bindSingleton(Object()); + } +} + +class YetAnotherWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MyBinder( + child: Container(), + ); + } + +} \ No newline at end of file diff --git a/lib/dependencies_flutter.dart b/lib/dependencies_flutter.dart new file mode 100644 index 0000000..b06cb7f --- /dev/null +++ b/lib/dependencies_flutter.dart @@ -0,0 +1,10 @@ +/// Dependency injection container for dart. +library dependencies_flutter; + +import 'package:dependencies/dependencies.dart'; +import 'package:flutter/material.dart'; +import 'package:quiver/check.dart'; + +part 'src/injector_widget.dart'; +part 'src/injector_widget_mixin.dart'; +part 'src/binding_injector_widget.dart'; diff --git a/lib/src/binding_injector_widget.dart b/lib/src/binding_injector_widget.dart new file mode 100644 index 0000000..9a3e154 --- /dev/null +++ b/lib/src/binding_injector_widget.dart @@ -0,0 +1,19 @@ +part of 'package:dependencies_flutter/dependencies_flutter.dart'; + +/// Utility base [Widget] to set up bindings. +abstract class BindingInjectorWidget extends StatelessWidget { + final Widget child; + const BindingInjectorWidget({Key key, @required this.child}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return InjectorWidget.bind( + binderFunc: configure, + child: child, + ); + } + + /// Create all the [Injector] bindings. + void configure(Binder binder); +} diff --git a/lib/src/injector_widget.dart b/lib/src/injector_widget.dart new file mode 100644 index 0000000..97c1353 --- /dev/null +++ b/lib/src/injector_widget.dart @@ -0,0 +1,69 @@ +part of 'package:dependencies_flutter/dependencies_flutter.dart'; + +/// A function used to add the bindings to an [Injector]. +typedef void BindFunc(Binder binder); + +/// [InheritedWidget] containing an [Injector]. +class InjectorWidget extends InheritedWidget { + final Injector _injector; + + const InjectorWidget._internal( + {@required Injector injector, Key key, @required Widget child}) + : this._injector = injector, + super(key: key, child: child); + + /// Creates an [InjectorWidget] based on an [Injector]. + factory InjectorWidget({ + Key key, + @required Injector injector, + @required Widget child, + }) { + checkNotNull(injector, message: () => "injector can't be null"); + checkNotNull(child, message: () => "child can't be null"); + + return InjectorWidget._internal(injector: injector, key: key, child: child); + } + + /// Creates an [InjectorWidget] based on a [BinderFunc]. + factory InjectorWidget.bind( + {Key key, + @required BindFunc binderFunc, + String name, + bool enableOverriding, + @required Widget child}) { + checkNotNull(binderFunc, message: () => "binder can't be null"); + checkNotNull(child, message: () => "child can't be null"); + + final builder = Injector.builder(); + if (name != null) builder.setName(name); + if (enableOverriding == true) builder.enableOverriding(); + binderFunc(builder); + final injector = builder.build(); + + return InjectorWidget._internal(injector: injector, key: key, child: child); + } + + @override + bool updateShouldNotify(InjectorWidget oldWidget) { + return oldWidget._injector != _injector; + } + + /// Gets an [Injector] from the [BuildContext]. + static Injector of(BuildContext context) { + InjectorWidget w = context.inheritFromWidgetOfExactType(InjectorWidget); + if (w == null) { + throw InjectorWidgetError._internal( + "No `InjectorWidget` was found in the context."); + } + return w._injector; + } +} + +/// Thrown when the [InjectorWidget] is not present. +class InjectorWidgetError extends StateError { + InjectorWidgetError._internal(String message) : super(message); + @override + String toString() { + return 'InjectorWidgetError: $message'; + } +} diff --git a/lib/src/injector_widget_mixin.dart b/lib/src/injector_widget_mixin.dart new file mode 100644 index 0000000..9c5b82d --- /dev/null +++ b/lib/src/injector_widget_mixin.dart @@ -0,0 +1,13 @@ +part of 'package:dependencies_flutter/dependencies_flutter.dart'; + +/// Utility mixin to easily use the injector in the [InjectorWidget]. +/// This can be applied to [State] or to [StatelessWidget] classes. +abstract class InjectorWidgetMixin { + Widget build(BuildContext context) { + final injector = InjectorWidget.of(context); + return buildWithInjector(context, injector); + } + + /// Build the [Widget] with the existing [Injector]. + Widget buildWithInjector(BuildContext context, Injector injector); +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..3830a95 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,13 @@ +name: dependencies_flutter +description: A simple and modular dependency injection system without using reflection. +version: 0.0.5 +homepage: https://github.com/marcguilera/dart_dependencies_flutter +author: marcguilera + +environment: + sdk: ">=2.0.0 <3.0.0" + +dependencies: + dependencies: ^0.0.5 + flutter: + sdk: flutter \ No newline at end of file