From f1a6f9f1a6807648acb98aeac00505790307ee7f Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 21 Oct 2020 15:56:06 -0300 Subject: [PATCH 01/71] change version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 829ef33c..b3c19b2e 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 2.0.1 +version: 2.1.0 homepage: https://github.com/Flutterando/modular environment: From 8c414353449b325278b504d6d42c1c326241a20d Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 21 Oct 2020 18:19:08 -0300 Subject: [PATCH 02/71] create modular interface and impl --- flutter_modular/analysis_options.yaml | 1 + .../lib/src/interfaces/modular_interface.dart | 17 ++++ flutter_modular/lib/src/modular_base.dart | 68 ++++++++++--- flutter_modular/lib/src/modular_impl.dart | 97 +++++++++++++++++++ .../test/modular_extension_test.dart | 13 +++ flutter_modular/test/modular_impl.dart | 1 + 6 files changed, 182 insertions(+), 15 deletions(-) create mode 100644 flutter_modular/lib/src/interfaces/modular_interface.dart create mode 100644 flutter_modular/lib/src/modular_impl.dart create mode 100644 flutter_modular/test/modular_extension_test.dart create mode 100644 flutter_modular/test/modular_impl.dart diff --git a/flutter_modular/analysis_options.yaml b/flutter_modular/analysis_options.yaml index 567202d4..cfa7ff4c 100644 --- a/flutter_modular/analysis_options.yaml +++ b/flutter_modular/analysis_options.yaml @@ -1,5 +1,6 @@ include: package:effective_dart/analysis_options.yaml + linter: rules: public_member_api_docs: false diff --git a/flutter_modular/lib/src/interfaces/modular_interface.dart b/flutter_modular/lib/src/interfaces/modular_interface.dart new file mode 100644 index 00000000..88b0210b --- /dev/null +++ b/flutter_modular/lib/src/interfaces/modular_interface.dart @@ -0,0 +1,17 @@ +import 'package:flutter/foundation.dart'; + +import '../../flutter_modular.dart'; + +abstract class ModularInterface { + bool debugMode = !kReleaseMode; + IModularNavigator navigatorDelegate; + + IModularNavigator get to; + IModularNavigator get link; + B get( + {Map params, + String module, + List typesInRequest, + B defaultValue}); + void dispose([String moduleName]); +} diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index 95f604d5..f9dfc8f4 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -1,14 +1,65 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; import '../flutter_modular.dart'; +import 'delegates/book_route_information_parser.dart'; +import 'delegates/book_router_delegate.dart'; import 'interfaces/child_module.dart'; +import 'interfaces/modular_interface.dart'; import 'interfaces/route_guard.dart'; +import 'modular_impl.dart'; import 'navigator/modular_navigator.dart'; import 'navigator/modular_navigator_interface.dart'; import 'routers/modular_router.dart'; +import 'utils/modular_arguments.dart'; import 'utils/old.dart'; +final _routeInformationParser = ModularRouteInformationParser(); +final _routerDelegate = ModularRouterDelegate(); +const Map _injectMap = {}; +// ignore: non_constant_identifier_names +final ModularInterface Modular = + ModularImpl(routerDelegate: _routerDelegate, injectiMap: _injectMap); + +extension ModularExtension on MaterialApp { + MaterialApp modular() { + final app = MaterialApp.router( + key: key, + scaffoldMessengerKey: scaffoldMessengerKey, + routeInformationProvider: routeInformationProvider, + backButtonDispatcher: backButtonDispatcher, + builder: builder, + title: title, + onGenerateTitle: onGenerateTitle, + color: color, + theme: theme, + darkTheme: darkTheme, + highContrastTheme: highContrastTheme, + highContrastDarkTheme: highContrastDarkTheme, + themeMode: themeMode, + locale: locale, + localizationsDelegates: localizationsDelegates, + localeListResolutionCallback: localeListResolutionCallback, + localeResolutionCallback: localeResolutionCallback, + supportedLocales: supportedLocales, + debugShowMaterialGrid: debugShowMaterialGrid, + showPerformanceOverlay: showPerformanceOverlay, + checkerboardRasterCacheImages: checkerboardRasterCacheImages, + checkerboardOffscreenLayers: checkerboardOffscreenLayers, + showSemanticsDebugger: showSemanticsDebugger, + debugShowCheckedModeBanner: debugShowCheckedModeBanner, + shortcuts: shortcuts, + actions: actions, + restorationScopeId: restorationScopeId, + //modular delegate + routeInformationParser: _routeInformationParser, + routerDelegate: _routerDelegate, + ); + + return app; + } +} + _debugPrintModular(String text) { if (Modular.debugMode) { debugPrint(text); @@ -27,7 +78,6 @@ class ModularNavigatorObserver extends NavigatorObserver { class Modular { static const String initialRoute = '/'; - static bool debugMode = !kReleaseMode; static bool isCupertino = false; static final Map _injectMap = {}; static ChildModule _initialModule; @@ -38,7 +88,7 @@ class Modular { static ModularArguments get args => _args?.copy(); static IModularNavigator navigatorDelegate; static List currentModule = []; - static Map> _navigators = + static final Map> _navigators = >{}; /// Return RouteLink of the current module @@ -99,7 +149,6 @@ class Modular { Modular.currentModule.add(name); } - /// Return Modular.navigatorKey /// /// ``` /// Modular.to; @@ -473,14 +522,3 @@ class Modular { _injectMap[tagText] = module; } } - -class ModularArguments { - final Map params; - final dynamic data; - - ModularArguments(this.params, this.data); - - ModularArguments copy() { - return ModularArguments(params, data); - } -} diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart new file mode 100644 index 00000000..310b8177 --- /dev/null +++ b/flutter_modular/lib/src/modular_impl.dart @@ -0,0 +1,97 @@ +import '../flutter_modular.dart'; +import 'delegates/book_router_delegate.dart'; +import 'interfaces/modular_interface.dart'; +import 'navigator/modular_navigator.dart'; + +class ModularImpl extends ModularInterface { + final ModularRouterDelegate routerDelegate; + final Map injectMap; + + ModularImpl({this.routerDelegate, this.injectMap}); + + @override + IModularNavigator get to { + return navigatorDelegate ?? + ModularNavigator(routerDelegate.navigatorKey.currentState); + } + + @override + // TODO: implement link + IModularNavigator get link => throw UnimplementedError(); + + @override + B get( + {Map params, + String module, + List typesInRequest, + B defaultValue}) { + if (B.toString() == 'dynamic') { + throw ModularError('not allow for dynamic values'); + } + + typesInRequest ??= []; + + if (module != null) { + return _getInjectableObject(module, + params: params, typesInRequest: typesInRequest); + } + + for (var key in injectMap.keys) { + final value = _getInjectableObject(key, + params: params, + disableError: true, + typesInRequest: typesInRequest, + checkKey: false); + if (value != null) { + return value; + } + } + + if (defaultValue != null) { + return defaultValue; + } + + throw ModularError('${B.toString()} not found'); + } + + B _getInjectableObject( + String tag, { + Map params, + bool disableError = false, + List typesInRequest, + bool checkKey = true, + }) { + B value; + if (!checkKey) { + value = injectMap[tag].getBind(params, typesInRequest: typesInRequest); + } else if (injectMap.containsKey(tag)) { + value = injectMap[tag].getBind(params, typesInRequest: typesInRequest); + } + if (value == null && !disableError) { + throw ModularError('${B.toString()} not found in module $tag'); + } + + return value; + } + + @override + void dispose([String moduleName]) { + if (B.toString() == 'dynamic') { + throw ModularError('not allow for dynamic values'); + } + + if (moduleName != null) { + _removeInjectableObject(moduleName); + } else { + for (var key in injectMap.keys) { + if (_removeInjectableObject(key)) { + break; + } + } + } + } + + bool _removeInjectableObject(String tag) { + return injectMap[tag].remove(); + } +} diff --git a/flutter_modular/test/modular_extension_test.dart b/flutter_modular/test/modular_extension_test.dart new file mode 100644 index 00000000..cdc020a4 --- /dev/null +++ b/flutter_modular/test/modular_extension_test.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_modular/flutter_modular.dart'; + +main() { + test('Initialized MaterialApp.modular sintaxe', () { + final theme = ThemeData.dark(); + final app = MaterialApp( + theme: theme, + ).modular(); + expect(app.theme, theme); + }); +} diff --git a/flutter_modular/test/modular_impl.dart b/flutter_modular/test/modular_impl.dart new file mode 100644 index 00000000..bae895ad --- /dev/null +++ b/flutter_modular/test/modular_impl.dart @@ -0,0 +1 @@ +main() {} From bc01b36971c4c9720b4bb4a123853c6290837463 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 21 Oct 2020 18:20:12 -0300 Subject: [PATCH 03/71] added route delegate --- .../modular_route_information_parser.dart | 30 ++++++++++++ .../lib/src/delegates/modular_route_path.dart | 11 +++++ .../delegates/modular_router_delegate.dart | 46 +++++++++++++++++++ .../lib/src/delegates/transitionDelegate.dart | 36 +++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 flutter_modular/lib/src/delegates/modular_route_information_parser.dart create mode 100644 flutter_modular/lib/src/delegates/modular_route_path.dart create mode 100644 flutter_modular/lib/src/delegates/modular_router_delegate.dart create mode 100644 flutter_modular/lib/src/delegates/transitionDelegate.dart diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart new file mode 100644 index 00000000..5881dbbb --- /dev/null +++ b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +import 'modular_route_path.dart'; + +class ModularRouteInformationParser + extends RouteInformationParser { + @override + Future parseRouteInformation( + RouteInformation routeInformation) async { + final uri = Uri.parse(routeInformation.location); + + if (uri.pathSegments.length >= 2) { + var remaining = uri.pathSegments[1]; + return BookRoutePath.details(int.tryParse(remaining)); + } else { + return BookRoutePath.home(); + } + } + + @override + RouteInformation restoreRouteInformation(BookRoutePath path) { + if (path.isHomePage) { + return RouteInformation(location: '/'); + } + if (path.isDetailsPage) { + return RouteInformation(location: '/book/${path.id}'); + } + return null; + } +} diff --git a/flutter_modular/lib/src/delegates/modular_route_path.dart b/flutter_modular/lib/src/delegates/modular_route_path.dart new file mode 100644 index 00000000..6e1f0951 --- /dev/null +++ b/flutter_modular/lib/src/delegates/modular_route_path.dart @@ -0,0 +1,11 @@ +class BookRoutePath { + final int id; + + BookRoutePath.home() : id = null; + + BookRoutePath.details(this.id); + + bool get isHomePage => id == null; + + bool get isDetailsPage => id != null; +} diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart new file mode 100644 index 00000000..018de9a4 --- /dev/null +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +import 'modular_route_path.dart'; +import 'transitionDelegate.dart'; + +class ModularRouterDelegate extends RouterDelegate + with ChangeNotifier, PopNavigatorRouterDelegateMixin { + final GlobalKey navigatorKey; + + ModularRouterDelegate() : navigatorKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Navigator( + key: navigatorKey, + transitionDelegate: NoAnimationTransitionDelegate(), + pages: [ + MaterialPage( + key: ValueKey('BooksListPage'), + child: Scaffold(), + ), + ], + onPopPage: (route, result) { + if (!route.didPop(result)) { + return false; + } + + notifyListeners(); + + return true; + }, + ); + } + + @override + Future setNewRoutePath(BookRoutePath path) async { + // if (path.isDetailsPage) { + // _selectedBook = books[path.id]; + // } + } + + void _handleBookTapped(dynamic book) { + // _selectedBook = book; + // notifyListeners(); + } +} diff --git a/flutter_modular/lib/src/delegates/transitionDelegate.dart b/flutter_modular/lib/src/delegates/transitionDelegate.dart new file mode 100644 index 00000000..9c0d7adb --- /dev/null +++ b/flutter_modular/lib/src/delegates/transitionDelegate.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +class NoAnimationTransitionDelegate extends TransitionDelegate { + @override + Iterable resolve({ + List newPageRouteHistory, + Map + locationToExitingPageRoute, + Map> + pageRouteToPagelessRoutes, + }) { + final results = []; + + for (final pageRoute in newPageRouteHistory) { + if (pageRoute.isWaitingForEnteringDecision) { + pageRoute.markForAdd(); + } + results.add(pageRoute); + } + + for (final exitingPageRoute in locationToExitingPageRoute.values) { + if (exitingPageRoute.isWaitingForExitingDecision) { + exitingPageRoute.markForRemove(); + final pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute]; + if (pagelessRoutes != null) { + for (final pagelessRoute in pagelessRoutes) { + pagelessRoute.markForRemove(); + } + } + } + + results.add(exitingPageRoute); + } + return results; + } +} From d37342a93962db7d9cd6b7fa1fef7e59a11c6255 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 21 Oct 2020 18:20:23 -0300 Subject: [PATCH 04/71] refactor --- flutter_modular/lib/src/inject/inject.dart | 1 + flutter_modular/lib/src/modular_base.dart | 4 ++-- flutter_modular/lib/src/modular_impl.dart | 2 +- flutter_modular/lib/src/transitions/transitions.dart | 1 + flutter_modular/lib/src/utils/modular_arguments.dart | 10 ++++++++++ flutter_modular/lib/src/utils/old.dart | 1 + 6 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 flutter_modular/lib/src/utils/modular_arguments.dart diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/lib/src/inject/inject.dart index 89a1ab9b..dd79b37b 100644 --- a/flutter_modular/lib/src/inject/inject.dart +++ b/flutter_modular/lib/src/inject/inject.dart @@ -1,4 +1,5 @@ import 'package:flutter/widgets.dart'; +import 'package:flutter_modular/src/utils/modular_arguments.dart'; import '../../flutter_modular.dart'; import '../modular_base.dart'; diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index f9dfc8f4..4c7a0e1f 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -2,8 +2,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../flutter_modular.dart'; -import 'delegates/book_route_information_parser.dart'; -import 'delegates/book_router_delegate.dart'; +import 'delegates/modular_route_information_parser.dart'; +import 'delegates/modular_router_delegate.dart'; import 'interfaces/child_module.dart'; import 'interfaces/modular_interface.dart'; import 'interfaces/route_guard.dart'; diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index 310b8177..cddc2b62 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -1,5 +1,5 @@ import '../flutter_modular.dart'; -import 'delegates/book_router_delegate.dart'; +import 'delegates/modular_router_delegate.dart'; import 'interfaces/modular_interface.dart'; import 'navigator/modular_navigator.dart'; diff --git a/flutter_modular/lib/src/transitions/transitions.dart b/flutter_modular/lib/src/transitions/transitions.dart index 8ddff6f9..cc15ca4d 100644 --- a/flutter_modular/lib/src/transitions/transitions.dart +++ b/flutter_modular/lib/src/transitions/transitions.dart @@ -1,4 +1,5 @@ import 'package:flutter/widgets.dart'; +import 'package:flutter_modular/src/utils/modular_arguments.dart'; import '../../flutter_modular.dart'; import 'page_transition.dart'; diff --git a/flutter_modular/lib/src/utils/modular_arguments.dart b/flutter_modular/lib/src/utils/modular_arguments.dart new file mode 100644 index 00000000..fbda1385 --- /dev/null +++ b/flutter_modular/lib/src/utils/modular_arguments.dart @@ -0,0 +1,10 @@ +class ModularArguments { + final Map params; + final dynamic data; + + ModularArguments(this.params, this.data); + + ModularArguments copy() { + return ModularArguments(params, data); + } +} diff --git a/flutter_modular/lib/src/utils/old.dart b/flutter_modular/lib/src/utils/old.dart index 68d6f9e6..0b814ab8 100644 --- a/flutter_modular/lib/src/utils/old.dart +++ b/flutter_modular/lib/src/utils/old.dart @@ -1,4 +1,5 @@ import '../../flutter_modular.dart'; +import 'modular_arguments.dart'; class Old { final ModularArguments args; From 65e86518b7c20b5f5de61d9deeb246f83d6ffaf4 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Thu, 22 Oct 2020 19:15:04 -0300 Subject: [PATCH 05/71] prepare to test --- .../example/lib/app/app_widget.dart | 4 +- .../lib/app/modules/home/home_widget.dart | 12 +- .../modules/tabs/modules/tab1/tab1_page.dart | 2 +- .../lib/app/modules/tabs/tabs_module.dart | 2 +- .../lib/app/modules/tabs/tabs_page.dart | 110 +-- .../example/lib/main_guardtest.dart | 4 +- flutter_modular/lib/flutter_modular.dart | 3 +- .../delegates/modular_router_delegate.dart | 28 +- flutter_modular/lib/src/inject/inject.dart | 2 +- .../lib/src/interfaces/modular_interface.dart | 8 +- .../modular_navigator_interface.dart | 7 - flutter_modular/lib/src/modular_base.dart | 744 +++++++----------- flutter_modular/lib/src/modular_impl.dart | 17 +- .../navigator/modular_navigator_outlet.dart | 2 +- .../modular_navigator.dart | 2 +- .../lib/src/routers/modular_router.dart | 24 +- .../lib/src/routers/route_link.dart | 42 +- .../lib/src/test/modular_test_interface.dart | 2 +- flutter_modular/lib/src/test/utils_test.dart | 10 +- .../lib/src/widgets/modular_app.dart | 8 +- .../lib/src/widgets/module_widget.dart | 4 +- .../lib/src/widgets/router_outlet.dart | 14 +- .../lib/src/widgets/router_outlet_list.dart | 73 -- .../lib/src/widgets/widget_module.dart | 4 +- .../test/abstract_router_test.dart | 82 +- flutter_modular/test/app/app_widget.dart | 2 +- .../test/app/modules/home/home_module.dart | 2 +- .../modular_module_test_interface_test.dart | 2 +- flutter_modular/test/modular_test.dart | 252 +++--- flutter_modular/test/modular_test_test.dart | 14 +- flutter_modular/test/new_route_test.dart | 23 + 31 files changed, 630 insertions(+), 875 deletions(-) rename flutter_modular/lib/src/{navigator => interfaces}/modular_navigator_interface.dart (96%) rename flutter_modular/lib/src/{navigator => routers}/modular_navigator.dart (98%) delete mode 100644 flutter_modular/lib/src/widgets/router_outlet_list.dart create mode 100644 flutter_modular/test/new_route_test.dart diff --git a/flutter_modular/example/lib/app/app_widget.dart b/flutter_modular/example/lib/app/app_widget.dart index 1e78ae79..bb91c105 100644 --- a/flutter_modular/example/lib/app/app_widget.dart +++ b/flutter_modular/example/lib/app/app_widget.dart @@ -6,8 +6,8 @@ class AppWidget extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( initialRoute: "/", - navigatorKey: Modular.navigatorKey, - onGenerateRoute: Modular.generateRoute, + // navigatorKey: Modular.navigatorKey, + // onGenerateRoute: Modular.generateRoute, ); } } diff --git a/flutter_modular/example/lib/app/modules/home/home_widget.dart b/flutter_modular/example/lib/app/modules/home/home_widget.dart index d7b2ed91..dca9f7b3 100644 --- a/flutter_modular/example/lib/app/modules/home/home_widget.dart +++ b/flutter_modular/example/lib/app/modules/home/home_widget.dart @@ -8,12 +8,12 @@ class HomeWidget extends ModularStatelessWidget { var c = Modular.get(); c.addListener(() { if (c.counter > 10) { - Modular.to.showDialog( - child: AlertDialog( - title: Text('Test'), - content: Text('Content'), - ), - ); + // Modular.to.showDialog( + // child: AlertDialog( + // title: Text('Test'), + // content: Text('Content'), + // ), + // ); } }); } diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart index 2fb6892f..c2d61b23 100644 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart +++ b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart @@ -18,7 +18,7 @@ class _Tab1PageState extends State { ), body: Center( child: RaisedButton(onPressed: () { - Modular.navigator.pushNamed('/page1'); + // Modular.navigator.pushNamed('/page1'); }), ), ); diff --git a/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart b/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart index aed96e09..9fa70014 100644 --- a/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart +++ b/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart @@ -10,6 +10,6 @@ class TabsModule extends ChildModule { @override List get routers => [ - ModularRouter('/', child: (_, args) => TabsPage()), + // ModularRouter('/', child: (_, args) => TabsPage()), ]; } diff --git a/flutter_modular/example/lib/app/modules/tabs/tabs_page.dart b/flutter_modular/example/lib/app/modules/tabs/tabs_page.dart index 194f09ff..e6b4dfb4 100644 --- a/flutter_modular/example/lib/app/modules/tabs/tabs_page.dart +++ b/flutter_modular/example/lib/app/modules/tabs/tabs_page.dart @@ -1,60 +1,60 @@ -import 'package:example/app/modules/tabs/tabs_bloc.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; +// import 'package:example/app/modules/tabs/tabs_bloc.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_modular/flutter_modular.dart'; -import 'modules/tab1/tab1_module.dart'; -import 'modules/tab2/tab2_module.dart'; +// import 'modules/tab1/tab1_module.dart'; +// import 'modules/tab2/tab2_module.dart'; -class TabsPage extends StatefulWidget { - final String title; - const TabsPage({Key key, this.title = "Tabs"}) : super(key: key); +// class TabsPage extends StatefulWidget { +// final String title; +// const TabsPage({Key key, this.title = "Tabs"}) : super(key: key); - @override - _TabsPageState createState() => _TabsPageState(); -} +// @override +// _TabsPageState createState() => _TabsPageState(); +// } -class _TabsPageState extends State { - var controller = RouterOutletListController(); - var currentIndex = 0; - @override - void initState() { - controller.listen((value) { - setState(() { - currentIndex = value; - }); - }); - super.initState(); - } +// class _TabsPageState extends State { +// var controller = RouterOutletListController(); +// var currentIndex = 0; +// @override +// void initState() { +// controller.listen((value) { +// setState(() { +// currentIndex = value; +// }); +// }); +// super.initState(); +// } - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - actions: [ - RaisedButton( - onPressed: () { - Modular.to.pushNamed('/home'); - }, - child: Text('HOME'), - ) - ], - ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.shopping_cart), - onPressed: () { - Modular.to.pushNamed("/shopping"); - }), - body: RouterOutletList( - modules: [Tab1Module(), Tab2Module()], controller: controller), - bottomNavigationBar: BottomNavigationBar( - currentIndex: currentIndex, - onTap: controller.changeModule, - items: [ - BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), - BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), - BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), - ]), - ); - } -} +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// appBar: AppBar( +// title: Text(widget.title), +// actions: [ +// RaisedButton( +// onPressed: () { +// Modular.to.pushNamed('/home'); +// }, +// child: Text('HOME'), +// ) +// ], +// ), +// floatingActionButton: FloatingActionButton( +// child: Icon(Icons.shopping_cart), +// onPressed: () { +// Modular.to.pushNamed("/shopping"); +// }), +// body: RouterOutletList( +// modules: [Tab1Module(), Tab2Module()], controller: controller), +// bottomNavigationBar: BottomNavigationBar( +// currentIndex: currentIndex, +// onTap: controller.changeModule, +// items: [ +// BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), +// BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), +// BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), +// ]), +// ); +// } +// } diff --git a/flutter_modular/example/lib/main_guardtest.dart b/flutter_modular/example/lib/main_guardtest.dart index d29b9199..fe39d88a 100644 --- a/flutter_modular/example/lib/main_guardtest.dart +++ b/flutter_modular/example/lib/main_guardtest.dart @@ -63,9 +63,9 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - navigatorKey: Modular.navigatorKey, + // navigatorKey: Modular.navigatorKey, initialRoute: '/', - onGenerateRoute: Modular.generateRoute, + // onGenerateRoute: Modular.generateRoute, ); } } diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 5fcac650..5e8baa36 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -7,9 +7,9 @@ export 'src/inject/inject.dart'; export 'src/interfaces/child_module.dart'; export 'src/interfaces/disposable.dart'; export 'src/interfaces/main_module.dart'; +export 'src/interfaces/modular_navigator_interface.dart'; export 'src/interfaces/route_guard.dart'; export 'src/modular_base.dart'; -export 'src/navigator/modular_navigator_interface.dart'; export 'src/routers/modular_router.dart'; export 'src/routers/route_link.dart'; export 'src/widgets/consumer_widget.dart'; @@ -17,5 +17,4 @@ export 'src/widgets/modular_app.dart'; export 'src/widgets/modular_stateful_widget_state.dart'; export 'src/widgets/modular_stateless_widget.dart'; export 'src/widgets/router_outlet.dart'; -export 'src/widgets/router_outlet_list.dart'; export 'src/widgets/widget_module.dart'; diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index 018de9a4..8051198d 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -7,7 +7,13 @@ class ModularRouterDelegate extends RouterDelegate with ChangeNotifier, PopNavigatorRouterDelegateMixin { final GlobalKey navigatorKey; - ModularRouterDelegate() : navigatorKey = GlobalKey(); + ModularRouterDelegate(this.navigatorKey); + + int counter = 0; + + @override + BookRoutePath get currentConfiguration => + counter == 0 ? BookRoutePath.home() : BookRoutePath.home(); @override Widget build(BuildContext context) { @@ -19,14 +25,16 @@ class ModularRouterDelegate extends RouterDelegate key: ValueKey('BooksListPage'), child: Scaffold(), ), + if (counter > 0) + MaterialPage( + key: ValueKey('BooksListPage2'), + child: Scaffold(), + ), ], onPopPage: (route, result) { if (!route.didPop(result)) { return false; } - - notifyListeners(); - return true; }, ); @@ -34,13 +42,15 @@ class ModularRouterDelegate extends RouterDelegate @override Future setNewRoutePath(BookRoutePath path) async { - // if (path.isDetailsPage) { - // _selectedBook = books[path.id]; - // } + if (path?.isDetailsPage == true) { + counter = 2; + print(path?.id); + } } - void _handleBookTapped(dynamic book) { + void handleBookTapped() { // _selectedBook = book; - // notifyListeners(); + counter = 2; + notifyListeners(); } } diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/lib/src/inject/inject.dart index dd79b37b..1e4ff9b7 100644 --- a/flutter_modular/lib/src/inject/inject.dart +++ b/flutter_modular/lib/src/inject/inject.dart @@ -39,7 +39,7 @@ class Inject { } } - ModularArguments get args => Modular.args; + // ModularArguments get args => Modular.args; /// get current module link RouteLink get link => Modular.link; diff --git a/flutter_modular/lib/src/interfaces/modular_interface.dart b/flutter_modular/lib/src/interfaces/modular_interface.dart index 88b0210b..df22ef34 100644 --- a/flutter_modular/lib/src/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_interface.dart @@ -1,10 +1,10 @@ -import 'package:flutter/foundation.dart'; - import '../../flutter_modular.dart'; abstract class ModularInterface { - bool debugMode = !kReleaseMode; - IModularNavigator navigatorDelegate; + bool get debugMode; + + String get initialRoute; + IModularNavigator get navigatorDelegate; IModularNavigator get to; IModularNavigator get link; diff --git a/flutter_modular/lib/src/navigator/modular_navigator_interface.dart b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart similarity index 96% rename from flutter_modular/lib/src/navigator/modular_navigator_interface.dart rename to flutter_modular/lib/src/interfaces/modular_navigator_interface.dart index db2560f8..1de9aa3e 100644 --- a/flutter_modular/lib/src/navigator/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart @@ -3,13 +3,6 @@ import 'package:flutter/widgets.dart'; abstract class IModularNavigator { String get path; String get modulePath; - NavigatorState get navigator; - - Future showDialog({ - Widget child, - WidgetBuilder builder, - bool barrierDismissible = true, - }); /// Navigate to a new screen. /// diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index 4c7a0e1f..782ed2fe 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -8,18 +8,19 @@ import 'interfaces/child_module.dart'; import 'interfaces/modular_interface.dart'; import 'interfaces/route_guard.dart'; import 'modular_impl.dart'; -import 'navigator/modular_navigator.dart'; -import 'navigator/modular_navigator_interface.dart'; +import 'routers/modular_navigator.dart'; import 'routers/modular_router.dart'; import 'utils/modular_arguments.dart'; import 'utils/old.dart'; -final _routeInformationParser = ModularRouteInformationParser(); -final _routerDelegate = ModularRouterDelegate(); +final _navigatorKey = GlobalKey(); + +final routeInformationParser = ModularRouteInformationParser(); +final routerDelegate = ModularRouterDelegate(_navigatorKey); const Map _injectMap = {}; // ignore: non_constant_identifier_names final ModularInterface Modular = - ModularImpl(routerDelegate: _routerDelegate, injectiMap: _injectMap); + ModularImpl(routerDelegate: routerDelegate, injectMap: _injectMap); extension ModularExtension on MaterialApp { MaterialApp modular() { @@ -51,9 +52,8 @@ extension ModularExtension on MaterialApp { shortcuts: shortcuts, actions: actions, restorationScopeId: restorationScopeId, - //modular delegate - routeInformationParser: _routeInformationParser, - routerDelegate: _routerDelegate, + routeInformationParser: routeInformationParser, + routerDelegate: routerDelegate, ); return app; @@ -66,459 +66,275 @@ _debugPrintModular(String text) { } } -class ModularNavigatorObserver extends NavigatorObserver { - @override - void didPop(Route route, Route previousRoute) { - Modular._navigators.forEach((key, value) { - if (value.currentState != null && key != null) {} - }); - super.didPop(route, previousRoute); - } -} - -class Modular { - static const String initialRoute = '/'; - static bool isCupertino = false; - static final Map _injectMap = {}; - static ChildModule _initialModule; - static ModularArguments _args; - static RouteLink _routeLink; - static Old _old = Old(); - static Old get old => _old; - static ModularArguments get args => _args?.copy(); - static IModularNavigator navigatorDelegate; - static List currentModule = []; - static final Map> _navigators = - >{}; - - /// Return RouteLink of the current module - /// - /// ``` - /// Modular.link; - /// ``` - static IModularNavigator get link { - if (navigatorDelegate == null) { - assert(_navigators.containsKey('app') == true, - '''Add Modular.navigatorKey in your MaterialApp; - - return MaterialApp( - navigatorKey: Modular.navigatorKey, - ... - -. - '''); - } - return navigatorDelegate ?? _routeLink?.copy(); - } - - /// Return Modular.navigator - /// Used for inside RouterOutlet - - static IModularNavigator get navigator { - return ModularNavigator(_navigators[currentModule.last].currentState); - } - - /// Add Navigator key for RouterOutlet - static GlobalKey outletNavigatorKey(String path) { - if (!_navigators.containsKey(path)) { - _navigators.addAll({path: GlobalKey()}); - } - return _navigators[path]; - } - - /// Remove Navigator key - static void removeOutletNavigatorKey(String path) { - if (_navigators.containsKey(path)) { - _navigators.remove(path); - } - } - - /// Add first position app in currentModule - static void updateCurrentModuleApp() { - if (Modular.currentModule.contains("app")) { - Modular.currentModule.remove("app"); - } - Modular.currentModule.insert(0, "app"); - } - - /// Add last position module in currentModule - static void updateCurrentModule(String name) { - if (Modular.currentModule.contains(name)) { - Modular.currentModule.remove(name); - } - Modular.currentModule.add(name); - } - - /// - /// ``` - /// Modular.to; - /// ``` - static IModularNavigator get to { - if (navigatorDelegate == null) { - assert(_navigators.containsKey('app') == true, - '''Add Modular.navigatorKey in your MaterialApp; - - return MaterialApp( - navigatorKey: Modular.navigatorKey, - ... - - - '''); - } - return navigatorDelegate ?? - ModularNavigator(_navigators['app'].currentState); - } - - @visibleForTesting - static void arguments({Map params, dynamic data}) { - _args = ModularArguments(params ?? {}, data); - } - - static GlobalKey get navigatorKey { - if (!_navigators.containsKey('app')) { - _navigators.addAll({'app': GlobalKey()}); - if (!currentModule.contains("app")) { - currentModule.add("app"); - } - } - return _navigators['app']; - } - - static void init(ChildModule module) { - _initialModule = module; - bindModule(module, "global=="); - } - - @visibleForTesting - static void bindModule(ChildModule module, [String path]) { - assert(module != null); - final name = module.runtimeType.toString(); - if (!_injectMap.containsKey(name)) { - module.paths.add(path); - _injectMap[name] = module; - module.instance(); - _debugPrintModular("-- ${module.runtimeType.toString()} INITIALIZED"); - } else { - _injectMap[name].paths.add(path); - } - } - - static void removeModule(ChildModule module, [String name]) { - name ??= module.runtimeType.toString(); - if (_injectMap.containsKey(name)) { - _injectMap[name].cleanInjects(); - _injectMap.remove(name); - if (_navigators.containsKey(name)) { - _navigators.remove(name); - currentModule.remove(name); - } - } - } - - static B get( - {Map params, - String module, - List typesInRequest, - B defaultValue}) { - if (B.toString() == 'dynamic') { - throw ModularError('not allow for dynamic values'); - } - - typesInRequest ??= []; - - if (module != null) { - return _getInjectableObject(module, - params: params, typesInRequest: typesInRequest); - } - - for (var key in _injectMap.keys) { - final value = _getInjectableObject(key, - params: params, - disableError: true, - typesInRequest: typesInRequest, - checkKey: false); - if (value != null) { - return value; - } - } - - if (defaultValue != null) { - return defaultValue; - } - - throw ModularError('${B.toString()} not found'); - } - - static B _getInjectableObject(String tag, - {Map params, - bool disableError = false, - List typesInRequest, - bool checkKey = true}) { - B value; - if (!checkKey) { - value = - _injectMap[tag].getBind(params, typesInRequest: typesInRequest); - } else if (_injectMap.containsKey(tag)) { - value = - _injectMap[tag].getBind(params, typesInRequest: typesInRequest); - } - if (value == null && !disableError) { - throw ModularError('${B.toString()} not found in module $tag'); - } - - return value; - } - - static void dispose([String module]) { - if (B.toString() == 'dynamic') { - throw ModularError('not allow for dynamic values'); - } - - if (module != null) { - _removeInjectableObject(module); - } else { - for (var key in _injectMap.keys) { - if (_removeInjectableObject(key)) { - break; - } - } - } - } - - static bool _removeInjectableObject(String tag) { - return _injectMap[tag].remove(); - } - - @visibleForTesting - static String prepareToRegex(String url) { - final newUrl = []; - for (var part in url.split('/')) { - var url = part.contains(":") ? "(.*?)" : part; - newUrl.add(url); - } - - return newUrl.join("/"); - } - - @visibleForTesting - static dynamic convertType(String value) { - if (int.tryParse(value) != null) { - return int.parse(value); - } else if (double.tryParse(value) != null) { - return double.parse(value); - } else if (value.toLowerCase() == 'true') { - return true; - } else if (value.toLowerCase() == 'false') { - return false; - } - - return value; - } - - @visibleForTesting - static bool searchRoute( - ModularRouter router, String routeNamed, String path) { - if (routeNamed.split('/').length != path.split('/').length) { - return false; - } - - if (routeNamed.contains('/:')) { - final regExp = RegExp( - "^${prepareToRegex(routeNamed)}\$", - caseSensitive: true, - ); - var r = regExp.firstMatch(path); - if (r != null) { - final params = {}; - var paramPos = 0; - final routeParts = routeNamed.split('/'); - final pathParts = path.split('/'); - - // print('Match! Processing $path as $routeNamed'); - - for (var routePart in routeParts) { - if (routePart.contains(":")) { - var paramName = routePart.replaceFirst(':', ''); - if (pathParts[paramPos].isNotEmpty) { - params[paramName] = pathParts[paramPos]; - routeNamed = - routeNamed.replaceFirst(routePart, params[paramName]); - } - } - paramPos++; - } - - // print('Result processed $path as $routeNamed'); - - if (routeNamed != path) { - router.params = null; - return false; - } - - router.params = params; - return true; - } - - router.params = null; - return false; - } - - return routeNamed == path; - } - - static RouteGuard _verifyGuard(List guards, String path) { - RouteGuard guard; - var realGuards = guards ?? []; - guard = realGuards.length == 0 - ? null - : guards.firstWhere((guard) => !guard.canActivate(path), - orElse: () => null); - - realGuards - .expand((c) => c.executors) - .forEach((c) => c.onGuarded(path, isActive: guard == null)); - - if (guard != null) { - throw ModularError("Path guarded : $path"); - } - return guard; - } - - static List _masterRouteGuards; - - static ModularRouter _searchInModule( - ChildModule module, String routerName, String path) { - path = "/$path".replaceAll('//', '/'); - final routers = module.routers; - routers.sort((preview, actual) { - return preview.routerName.contains('/:') ? 1 : 0; - }); - for (var route in routers) { - final tempRouteName = - (routerName + route.routerName).replaceFirst('//', '/'); - if (route.child == null) { - _masterRouteGuards = route.guards; - var _routerName = - ('$routerName${route.routerName}/').replaceFirst('//', '/'); - ModularRouter router; - if (_routerName == path || _routerName == "$path/") { - final guard = _verifyGuard(route.guards, path); - if (guard != null) { - return null; - } - router = route.module.routers[0]; - if (router.module != null) { - var _routerName = - (routerName + route.routerName).replaceFirst('//', '/'); - router = _searchInModule(route.module, _routerName, path); - } - } else { - router = _searchInModule(route.module, _routerName, path); - } - - if (router != null) { - router = router.modulePath == null - ? router.copyWith(modulePath: tempRouteName) - : router; - if (_routerName == path || _routerName == "$path/") { - final guard = _verifyGuard(router.guards, path); - if (guard != null) { - return null; - } - } - - if (router.transition == TransitionType.defaultTransition) { - router = router.copyWith( - transition: route.transition, - customTransition: route.customTransition, - ); - } - bindModule(route.module, path); - return router; - } - } else { - if (searchRoute(route, tempRouteName, path)) { - var guards = _prepareGuardList(_masterRouteGuards, route.guards); - _masterRouteGuards = null; - var guard = _verifyGuard(guards, path); - if ((tempRouteName == path || tempRouteName == "$path/") && - path != '/') { - guard = _verifyGuard(guards, path); - } - return guard == null ? route : null; - } - } - } - return null; - } - - static List _prepareGuardList( - List moduleGuard, List routeGuard) { - if (moduleGuard == null) { - moduleGuard = []; - } - if (routeGuard == null) { - routeGuard = []; - } - - return List.from([...moduleGuard, ...routeGuard]); - } - - @visibleForTesting - static ModularRouter selectRoute(String path, [ChildModule module]) { - if (path.isEmpty) { - throw Exception("Router can not be empty"); - } - final route = _searchInModule(module ?? _initialModule, "", path); - return route; - } - - static void oldProccess(Old $old) { - if ($old?.args != null) _args = $old?.args?.copy(); - if ($old?.link != null) _routeLink = $old?.link?.copy(); - } - - static Route generateRoute(RouteSettings settings, - [ChildModule module, void Function(String) onChangeRoute]) { - final isRouterOutlet = module != null; - final path = settings.name; - var router = selectRoute(path, module); - if (router == null) { - return null; - } - if (!isRouterOutlet) { - _old = Old( - args: args, - link: link, - ); - updateCurrentModule("app"); - } - - _args = ModularArguments(router.params, settings.arguments); - - _routeLink = RouteLink(path: path, modulePath: router.modulePath); - - if (settings.name == Modular.initialRoute) { - router = router.copyWith(transition: TransitionType.noTransition); - } - - if (onChangeRoute != null) { - onChangeRoute(path); - } - - return router.getPageRoute( - settings: settings, - injectMap: _injectMap, - isRouterOutlet: isRouterOutlet); - } - - static void addCoreInit(ChildModule module) { - var tagText = module.runtimeType.toString(); - addCoreInitFromTag(module, tagText); - } - - static void addCoreInitFromTag(ChildModule module, String tagText) { - module.instance(); - _injectMap[tagText] = module; - } -} +// class _Modular { +// static ChildModule _initialModule; +// static ModularArguments _args; +// static ModularArguments get args => _args?.copy(); +// static List currentModule = []; +// static final Map> _navigators = +// >{}; + +// static void init(ChildModule module) { +// _initialModule = module; +// bindModule(module, "global=="); +// } + +// @visibleForTesting +// static void bindModule(ChildModule module, [String path]) { +// assert(module != null); +// final name = module.runtimeType.toString(); +// if (!_injectMap.containsKey(name)) { +// module.paths.add(path); +// _injectMap[name] = module; +// module.instance(); +// _debugPrintModular("-- ${module.runtimeType.toString()} INITIALIZED"); +// } else { +// _injectMap[name].paths.add(path); +// } +// } + +// static void removeModule(ChildModule module, [String name]) { +// name ??= module.runtimeType.toString(); +// if (_injectMap.containsKey(name)) { +// _injectMap[name].cleanInjects(); +// _injectMap.remove(name); +// if (_navigators.containsKey(name)) { +// _navigators.remove(name); +// currentModule.remove(name); +// } +// } +// } + +// @visibleForTesting +// static String prepareToRegex(String url) { +// final newUrl = []; +// for (var part in url.split('/')) { +// var url = part.contains(":") ? "(.*?)" : part; +// newUrl.add(url); +// } + +// return newUrl.join("/"); +// } + +// @visibleForTesting +// static dynamic convertType(String value) { +// if (int.tryParse(value) != null) { +// return int.parse(value); +// } else if (double.tryParse(value) != null) { +// return double.parse(value); +// } else if (value.toLowerCase() == 'true') { +// return true; +// } else if (value.toLowerCase() == 'false') { +// return false; +// } + +// return value; +// } + +// @visibleForTesting +// static bool searchRoute( +// ModularRouter router, String routeNamed, String path) { +// if (routeNamed.split('/').length != path.split('/').length) { +// return false; +// } + +// if (routeNamed.contains('/:')) { +// final regExp = RegExp( +// "^${prepareToRegex(routeNamed)}\$", +// caseSensitive: true, +// ); +// var r = regExp.firstMatch(path); +// if (r != null) { +// final params = {}; +// var paramPos = 0; +// final routeParts = routeNamed.split('/'); +// final pathParts = path.split('/'); + +// // print('Match! Processing $path as $routeNamed'); + +// for (var routePart in routeParts) { +// if (routePart.contains(":")) { +// var paramName = routePart.replaceFirst(':', ''); +// if (pathParts[paramPos].isNotEmpty) { +// params[paramName] = pathParts[paramPos]; +// routeNamed = +// routeNamed.replaceFirst(routePart, params[paramName]); +// } +// } +// paramPos++; +// } + +// // print('Result processed $path as $routeNamed'); + +// if (routeNamed != path) { +// router.params = null; +// return false; +// } + +// router.params = params; +// return true; +// } + +// router.params = null; +// return false; +// } + +// return routeNamed == path; +// } + +// static RouteGuard _verifyGuard(List guards, String path) { +// RouteGuard guard; +// var realGuards = guards ?? []; +// guard = realGuards.length == 0 +// ? null +// : guards.firstWhere((guard) => !guard.canActivate(path), +// orElse: () => null); + +// realGuards +// .expand((c) => c.executors) +// .forEach((c) => c.onGuarded(path, isActive: guard == null)); + +// if (guard != null) { +// throw ModularError("Path guarded : $path"); +// } +// return guard; +// } + +// static List _masterRouteGuards; + +// static ModularRouter _searchInModule( +// ChildModule module, String routerName, String path) { +// path = "/$path".replaceAll('//', '/'); +// final routers = module.routers; +// routers.sort((preview, actual) { +// return preview.routerName.contains('/:') ? 1 : 0; +// }); +// for (var route in routers) { +// final tempRouteName = +// (routerName + route.routerName).replaceFirst('//', '/'); +// if (route.child == null) { +// _masterRouteGuards = route.guards; +// var _routerName = +// ('$routerName${route.routerName}/').replaceFirst('//', '/'); +// ModularRouter router; +// if (_routerName == path || _routerName == "$path/") { +// final guard = _verifyGuard(route.guards, path); +// if (guard != null) { +// return null; +// } +// router = route.module.routers[0]; +// if (router.module != null) { +// var _routerName = +// (routerName + route.routerName).replaceFirst('//', '/'); +// router = _searchInModule(route.module, _routerName, path); +// } +// } else { +// router = _searchInModule(route.module, _routerName, path); +// } + +// if (router != null) { +// router = router.modulePath == null +// ? router.copyWith(modulePath: tempRouteName) +// : router; +// if (_routerName == path || _routerName == "$path/") { +// final guard = _verifyGuard(router.guards, path); +// if (guard != null) { +// return null; +// } +// } + +// if (router.transition == TransitionType.defaultTransition) { +// router = router.copyWith( +// transition: route.transition, +// customTransition: route.customTransition, +// ); +// } +// bindModule(route.module, path); +// return router; +// } +// } else { +// if (searchRoute(route, tempRouteName, path)) { +// var guards = _prepareGuardList(_masterRouteGuards, route.guards); +// _masterRouteGuards = null; +// var guard = _verifyGuard(guards, path); +// if ((tempRouteName == path || tempRouteName == "$path/") && +// path != '/') { +// guard = _verifyGuard(guards, path); +// } +// return guard == null ? route : null; +// } +// } +// } +// return null; +// } + +// static List _prepareGuardList( +// List moduleGuard, List routeGuard) { +// if (moduleGuard == null) { +// moduleGuard = []; +// } +// if (routeGuard == null) { +// routeGuard = []; +// } + +// return List.from([...moduleGuard, ...routeGuard]); +// } + +// @visibleForTesting +// static ModularRouter selectRoute(String path, [ChildModule module]) { +// if (path.isEmpty) { +// throw Exception("Router can not be empty"); +// } +// final route = _searchInModule(module ?? _initialModule, "", path); +// return route; +// } + +// static void oldProccess(Old $old) { +// if ($old?.args != null) _args = $old?.args?.copy(); +// if ($old?.link != null) _routeLink = $old?.link?.copy(); +// } + +// static Route generateRoute(RouteSettings settings, +// [ChildModule module, void Function(String) onChangeRoute]) { +// final isRouterOutlet = module != null; +// final path = settings.name; +// var router = selectRoute(path, module); +// if (router == null) { +// return null; +// } +// if (!isRouterOutlet) { +// _old = Old( +// args: args, +// link: link, +// ); +// //updateCurrentModule("app"); +// } + +// _args = ModularArguments(router.params, settings.arguments); + +// _routeLink = RouteLink(path: path, modulePath: router.modulePath); + +// if (settings.name == Modular.initialRoute) { +// router = router.copyWith(transition: TransitionType.noTransition); +// } + +// if (onChangeRoute != null) { +// onChangeRoute(path); +// } + +// return router.getPageRoute( +// settings: settings, +// injectMap: _injectMap, +// isRouterOutlet: isRouterOutlet); +// } + +// static void addCoreInit(ChildModule module) { +// var tagText = module.runtimeType.toString(); +// addCoreInitFromTag(module, tagText); +// } + +// static void addCoreInitFromTag(ChildModule module, String tagText) { +// module.instance(); +// _injectMap[tagText] = module; +// } +// } diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index cddc2b62..63bdd558 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -1,13 +1,17 @@ +import 'package:flutter/foundation.dart'; + import '../flutter_modular.dart'; import 'delegates/modular_router_delegate.dart'; import 'interfaces/modular_interface.dart'; -import 'navigator/modular_navigator.dart'; +import 'routers/modular_navigator.dart'; -class ModularImpl extends ModularInterface { +class ModularImpl implements ModularInterface { final ModularRouterDelegate routerDelegate; final Map injectMap; + final IModularNavigator navigatorDelegate; - ModularImpl({this.routerDelegate, this.injectMap}); + const ModularImpl( + {this.routerDelegate, this.injectMap, this.navigatorDelegate}); @override IModularNavigator get to { @@ -16,9 +20,14 @@ class ModularImpl extends ModularInterface { } @override - // TODO: implement link IModularNavigator get link => throw UnimplementedError(); + @override + bool get debugMode => !kReleaseMode; + + @override + String get initialRoute => '/'; + @override B get( {Map params, diff --git a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart b/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart index 6e8abf22..3b1143fd 100644 --- a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart +++ b/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; -import 'modular_navigator.dart'; +import '../routers/modular_navigator.dart'; class ModularNavigatorOutlet extends ModularNavigator { final NavigatorState global; diff --git a/flutter_modular/lib/src/navigator/modular_navigator.dart b/flutter_modular/lib/src/routers/modular_navigator.dart similarity index 98% rename from flutter_modular/lib/src/navigator/modular_navigator.dart rename to flutter_modular/lib/src/routers/modular_navigator.dart index 3e1be7de..ab3bc5d1 100644 --- a/flutter_modular/lib/src/navigator/modular_navigator.dart +++ b/flutter_modular/lib/src/routers/modular_navigator.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import '../../flutter_modular.dart'; -import 'modular_navigator_interface.dart'; +import '../interfaces/modular_navigator_interface.dart'; class ModularNavigator implements IModularNavigator { final NavigatorState navigator; diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index 91546f3a..a4c70eb1 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/utils/modular_arguments.dart'; import '../../flutter_modular.dart'; import '../interfaces/child_module.dart'; import '../interfaces/route_guard.dart'; @@ -271,8 +272,8 @@ class ModularRouter { dispose: (old, actual) { final trash = []; if (!isRouterOutlet) { - Modular.oldProccess(old); - Modular.updateCurrentModuleApp(); + // Modular.oldProccess(old); + // Modular.updateCurrentModuleApp(); } if (actual.isCurrent) { return; @@ -321,20 +322,15 @@ class ModularRouter { if (routeGenerator != null) { return routeGenerator(widgetBuilder, settings); } - return Modular.isCupertino - ? CupertinoPageRoute( - settings: settings, - builder: widgetBuilder, - ) - : MaterialPageRoute( - settings: settings, - builder: widgetBuilder, - ); + return MaterialPageRoute( + settings: settings, + builder: widgetBuilder, + ); } else { var selectTransition = _transitions[transition]; return selectTransition((context, args) { return disposablePage; - }, Modular.args, duration, settings); + }, null, duration, settings); } } } @@ -388,8 +384,8 @@ class __DisposableWidgetState extends State<_DisposableWidget> { @override void initState() { super.initState(); - old = Modular.old; - args = Modular.args; + // old = Modular.old; + // args = Modular.args; } @override diff --git a/flutter_modular/lib/src/routers/route_link.dart b/flutter_modular/lib/src/routers/route_link.dart index d7a823b9..b6e7c839 100644 --- a/flutter_modular/lib/src/routers/route_link.dart +++ b/flutter_modular/lib/src/routers/route_link.dart @@ -1,85 +1,71 @@ import 'package:flutter/widgets.dart'; + import '../../flutter_modular.dart'; class RouteLink extends IModularNavigator { final String path; final String modulePath; + final NavigatorState navigator; - RouteLink({this.path, this.modulePath = "/"}); + RouteLink(this.navigator, {this.path, this.modulePath = "/"}); RouteLink copy() { - return RouteLink(path: path, modulePath: modulePath); + return RouteLink(navigator, path: path, modulePath: modulePath); } @override - bool canPop() => Modular.navigator.canPop(); + bool canPop() => navigator.canPop(); @override Future maybePop([T result]) { - return Modular.navigator.maybePop(result); + return navigator.maybePop(result); } @override - void pop([T result]) => Modular.navigator.pop(result); + void pop([T result]) => navigator.pop(result); @override Future popAndPushNamed( String routeName, {TO result, Object arguments}) => - Modular.navigator.popAndPushNamed(_checkpath(routeName), + navigator.popAndPushNamed(_checkpath(routeName), result: result, arguments: arguments); @override void popUntil(bool Function(Route) predicate) => - Modular.navigator.popUntil(predicate); + navigator.popUntil(predicate); @override - Future push(Route route) => - Modular.navigator.push(route); + Future push(Route route) => navigator.push(route); @override Future pushNamed(String routeName, {Object arguments}) => - Modular.navigator.pushNamed(_checkpath(routeName), arguments: arguments); + navigator.pushNamed(_checkpath(routeName), arguments: arguments); @override Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, {Object arguments}) => - Modular.navigator.pushNamedAndRemoveUntil( - _checkpath(newRouteName), predicate, + navigator.pushNamedAndRemoveUntil(_checkpath(newRouteName), predicate, arguments: arguments); @override Future pushReplacementNamed( String routeName, {TO result, Object arguments}) => - Modular.navigator.pushReplacementNamed(_checkpath(routeName), + navigator.pushReplacementNamed(_checkpath(routeName), result: result, arguments: arguments); @override Future pushReplacement( Route newRoute, {TO result}) => - Modular.navigator.pushReplacement(newRoute, result: result); - - @override - Future showDialog({ - @deprecated Widget child, - @required WidgetBuilder builder, - bool barrierDismissible = true, - }) => - Modular.navigator.showDialog( - builder: builder, - child: child, - barrierDismissible: barrierDismissible); + navigator.pushReplacement(newRoute, result: result); String _checkpath(String routeName) { routeName = routeName[0] == '/' ? routeName : '/$routeName'; var newPath = "$modulePath$routeName".replaceAll('//', '/'); return newPath; } - - @override - NavigatorState get navigator => Modular.to.navigator; } diff --git a/flutter_modular/lib/src/test/modular_test_interface.dart b/flutter_modular/lib/src/test/modular_test_interface.dart index c672613b..c4045702 100644 --- a/flutter_modular/lib/src/test/modular_test_interface.dart +++ b/flutter_modular/lib/src/test/modular_test_interface.dart @@ -76,7 +76,7 @@ abstract class IModularTest { @visibleForTesting void memoryManage(ModularTestType modularTestType) { if (modularTestType == ModularTestType.resetModules) { - Modular.removeModule(module); + // Modular.removeModule(module); } } diff --git a/flutter_modular/lib/src/test/utils_test.dart b/flutter_modular/lib/src/test/utils_test.dart index 11b90ec9..bcebf59d 100644 --- a/flutter_modular/lib/src/test/utils_test.dart +++ b/flutter_modular/lib/src/test/utils_test.dart @@ -4,7 +4,7 @@ import '../../flutter_modular.dart'; void initModule(ChildModule module, {List changeBinds, bool initialModule}) { - Modular.debugMode = false; + //Modular.debugMode = false; final list = module.binds; final changedList = List.from(list); for (var item in list ?? []) { @@ -18,9 +18,9 @@ void initModule(ChildModule module, } module.changeBinds(changedList); if (initialModule ?? false) { - Modular.init(module); + // Modular.init(module); } else { - Modular.bindModule(module); + // Modular.bindModule(module); } } @@ -36,8 +36,8 @@ Widget buildTestableWidget(Widget widget) { child: MaterialApp( home: widget, initialRoute: '/', - navigatorKey: Modular.navigatorKey, - onGenerateRoute: Modular.generateRoute, + // navigatorKey: Modular.navigatorKey, + // onGenerateRoute: Modular.generateRoute, ), ); } diff --git a/flutter_modular/lib/src/widgets/modular_app.dart b/flutter_modular/lib/src/widgets/modular_app.dart index 69001f25..312de05f 100644 --- a/flutter_modular/lib/src/widgets/modular_app.dart +++ b/flutter_modular/lib/src/widgets/modular_app.dart @@ -4,15 +4,11 @@ import '../interfaces/main_module.dart'; class ModularApp extends StatefulWidget { final MainModule module; - final bool isCupertino; ModularApp({ Key key, this.module, - this.isCupertino = false, - }) : super(key: key) { - Modular.isCupertino = isCupertino; - } + }) : super(key: key); @override _ModularAppState createState() => _ModularAppState(); @@ -22,7 +18,7 @@ class _ModularAppState extends State { @override void initState() { super.initState(); - Modular.init(widget.module); + // Modular.init(widget.module); } @override diff --git a/flutter_modular/lib/src/widgets/module_widget.dart b/flutter_modular/lib/src/widgets/module_widget.dart index 18af9c93..81e847b5 100644 --- a/flutter_modular/lib/src/widgets/module_widget.dart +++ b/flutter_modular/lib/src/widgets/module_widget.dart @@ -87,7 +87,7 @@ class _ModularProviderState extends State { @override void initState() { super.initState(); - Modular.addCoreInit(widget.module); + //Modular.addCoreInit(widget.module); _debugPrintModular("-- ${widget.module.runtimeType} INITIALIZED"); } @@ -99,7 +99,7 @@ class _ModularProviderState extends State { @override void dispose() { super.dispose(); - Modular.removeModule(widget.module); + //Modular.removeModule(widget.module); _debugPrintModular("-- ${widget.module.runtimeType} DISPOSED"); } } diff --git a/flutter_modular/lib/src/widgets/router_outlet.dart b/flutter_modular/lib/src/widgets/router_outlet.dart index 9b4de34f..85fcffc6 100644 --- a/flutter_modular/lib/src/widgets/router_outlet.dart +++ b/flutter_modular/lib/src/widgets/router_outlet.dart @@ -14,7 +14,7 @@ class RouterOutlet extends StatefulWidget { Key key, @required this.module, this.navigatorKey, - this.initialRoute = Modular.initialRoute, + this.initialRoute = '/', this.keepAlive = true, this.onChangeRoute, }) : super(key: key) { @@ -31,8 +31,8 @@ class _RouterOutletState extends State @override void initState() { super.initState(); - _key = widget.navigatorKey ?? - Modular.outletNavigatorKey(widget.module.runtimeType.toString()); + // _key = widget.navigatorKey ?? + // Modular.outletNavigatorKey(widget.module.runtimeType.toString()); } @override @@ -47,10 +47,10 @@ class _RouterOutletState extends State child: Navigator( key: _key, initialRoute: widget.initialRoute, - onGenerateRoute: (setting) { - return Modular.generateRoute( - setting, widget.module, widget.onChangeRoute); - }, + // onGenerateRoute: (setting) { + // return Modular.generateRoute( + // setting, widget.module, widget.onChangeRoute); + // }, ), ), ); diff --git a/flutter_modular/lib/src/widgets/router_outlet_list.dart b/flutter_modular/lib/src/widgets/router_outlet_list.dart deleted file mode 100644 index f2be57d6..00000000 --- a/flutter_modular/lib/src/widgets/router_outlet_list.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; -import 'package:flutter_modular/src/widgets/router_outlet.dart'; - -import '../modular_base.dart'; - -class RouterOutletList extends StatefulWidget { - final List modules; - final ScrollPhysics physics; - final RouterOutletListController controller; - const RouterOutletList( - {Key key, - @required this.modules, - this.physics = const NeverScrollableScrollPhysics(), - @required this.controller}) - : super(key: key); - @override - _RouterOutletListState createState() => _RouterOutletListState(); -} - -class _RouterOutletListState extends State { - @override - void initState() { - widget.controller.init(widget.modules); - super.initState(); - } - - @override - void dispose() { - widget.controller._dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return PageView( - physics: widget.physics, - controller: widget.controller._pageController, - onPageChanged: widget.controller.changeModule, - children: widget.modules - .map((e) => RouterOutlet( - module: e, - )) - .toList()); - } -} - -class RouterOutletListController { - final _pageController = PageController(); - List _modules; - ValueChanged _listen; - void init(List modules) { - _modules = modules; - Modular.updateCurrentModule(modules[0].runtimeType.toString()); - } - - void changeModule(int index) { - final name = _modules[index].runtimeType.toString(); - Modular.updateCurrentModule(name); - _pageController.jumpToPage(index); - if (_listen != null) { - _listen(index); - } - } - - void listen(ValueChanged current) { - _listen = current; - } - - void _dispose() { - _pageController.dispose(); - } -} diff --git a/flutter_modular/lib/src/widgets/widget_module.dart b/flutter_modular/lib/src/widgets/widget_module.dart index 18af9c93..a51b2dd0 100644 --- a/flutter_modular/lib/src/widgets/widget_module.dart +++ b/flutter_modular/lib/src/widgets/widget_module.dart @@ -87,7 +87,7 @@ class _ModularProviderState extends State { @override void initState() { super.initState(); - Modular.addCoreInit(widget.module); + // Modular.addCoreInit(widget.module); _debugPrintModular("-- ${widget.module.runtimeType} INITIALIZED"); } @@ -99,7 +99,7 @@ class _ModularProviderState extends State { @override void dispose() { super.dispose(); - Modular.removeModule(widget.module); + // Modular.removeModule(widget.module); _debugPrintModular("-- ${widget.module.runtimeType} DISPOSED"); } } diff --git a/flutter_modular/test/abstract_router_test.dart b/flutter_modular/test/abstract_router_test.dart index dc89b9db..9c15c13c 100644 --- a/flutter_modular/test/abstract_router_test.dart +++ b/flutter_modular/test/abstract_router_test.dart @@ -1,46 +1,46 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_test/flutter_test.dart'; +// import 'package:flutter/material.dart'; +// import 'package:flutter_modular/flutter_modular.dart'; +// import 'package:flutter_test/flutter_test.dart'; -class DynamicModule extends ChildModule { - @override - List get binds => []; +// class DynamicModule extends ChildModule { +// @override +// List get binds => []; - @override - List get routers => [ - ModularRouter('/', child: (_, __) => Container()), - ModularRouter('/home', child: (_, __) => Container()), - ModularRouter('/product', child: (_, __) => Container()), - ModularRouter('/product/:id', child: (_, __) => Container()), - ModularRouter('/:id', child: (_, __) => Container()), - ]; -} +// @override +// List get routers => [ +// ModularRouter('/', child: (_, __) => Container()), +// ModularRouter('/home', child: (_, __) => Container()), +// ModularRouter('/product', child: (_, __) => Container()), +// ModularRouter('/product/:id', child: (_, __) => Container()), +// ModularRouter('/:id', child: (_, __) => Container()), +// ]; +// } -main() { - setUpAll(() { - Modular.init(DynamicModule()); - }); +// main() { +// setUpAll(() { +// Modular.init(DynamicModule()); +// }); - group("Dynamic router", () { - test('Test Get ModularRouter', () { - var router = Modular.selectRoute("/"); - expect(router.routerName, "/"); - }); - test('Test Get ModularRouter dynamic', () { - var router = Modular.selectRoute("/1"); - expect(router.routerName, "/:id"); - }); - test('Test Get ModularRouter home', () { - var router = Modular.selectRoute("/home"); - expect(router.routerName, "/home"); - }); +// group("Dynamic router", () { +// test('Test Get ModularRouter', () { +// var router = Modular.selectRoute("/"); +// expect(router.routerName, "/"); +// }); +// test('Test Get ModularRouter dynamic', () { +// var router = Modular.selectRoute("/1"); +// expect(router.routerName, "/:id"); +// }); +// test('Test Get ModularRouter home', () { +// var router = Modular.selectRoute("/home"); +// expect(router.routerName, "/home"); +// }); - test('Test Get ModularRouter product', () { - expect(Modular.selectRoute("/product")?.routerName, "/product"); - }); - test('Test Get ModularRouter product id', () { - var router = Modular.selectRoute("/product/1"); - expect(router.routerName, "/product/:id"); - }); - }); -} +// test('Test Get ModularRouter product', () { +// expect(Modular.selectRoute("/product")?.routerName, "/product"); +// }); +// test('Test Get ModularRouter product id', () { +// var router = Modular.selectRoute("/product/1"); +// expect(router.routerName, "/product/:id"); +// }); +// }); +// } diff --git a/flutter_modular/test/app/app_widget.dart b/flutter_modular/test/app/app_widget.dart index c76cb0c6..380d5966 100644 --- a/flutter_modular/test/app/app_widget.dart +++ b/flutter_modular/test/app/app_widget.dart @@ -6,7 +6,7 @@ class AppWidget extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( initialRoute: "/", - onGenerateRoute: Modular.generateRoute, + // onGenerateRoute: Modular.generateRoute, onUnknownRoute: (context) { return MaterialPageRoute( builder: (context) => Scaffold( diff --git a/flutter_modular/test/app/modules/home/home_module.dart b/flutter_modular/test/app/modules/home/home_module.dart index 44aba7bb..46c8e723 100644 --- a/flutter_modular/test/app/modules/home/home_module.dart +++ b/flutter_modular/test/app/modules/home/home_module.dart @@ -64,7 +64,7 @@ class _ModularArgumentsPageState extends State { @override void initState() { super.initState(); - _id = Modular.args.data; + // _id = Modular.args.data; } @override diff --git a/flutter_modular/test/modular_module_test_interface_test.dart b/flutter_modular/test/modular_module_test_interface_test.dart index 6beca5b2..310c8fdc 100644 --- a/flutter_modular/test/modular_module_test_interface_test.dart +++ b/flutter_modular/test/modular_module_test_interface_test.dart @@ -244,7 +244,7 @@ void main() { expect(titleFinder, findsOneWidget); }); testWidgets("Modular Arguments Page id", (tester) async { - Modular.arguments(data: 10); + // Modular.arguments(data: 10); await tester.pumpWidget(buildTestableWidget(ModularArgumentsPage())); final titleFinder = find.text("10"); expect(titleFinder, findsOneWidget); diff --git a/flutter_modular/test/modular_test.dart b/flutter_modular/test/modular_test.dart index 097ea301..5c2d9dec 100644 --- a/flutter_modular/test/modular_test.dart +++ b/flutter_modular/test/modular_test.dart @@ -1,126 +1,126 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'app/app_module.dart'; - -void main() { - setUpAll(() { - Modular.init(AppModule()); - }); - - group("Group router", () { - test('Test Get ModularRouter', () { - expect(Modular.selectRoute("/"), isA()); - }); - test('Test Get module ModularRouter', () { - expect(Modular.selectRoute("home/"), isA()); - expect(Modular.selectRoute("/home/"), isA()); - var router = Modular.selectRoute("/home"); - expect(router.routerName, '/'); - }); - - test('router empty', () { - expect(() => Modular.selectRoute(""), throwsException); - }); - - test('prepare to regex', () { - expect(Modular.prepareToRegex('/home/list/:id'), '/home/list/(.*?)'); - expect(Modular.prepareToRegex('/home/list/:id/'), '/home/list/(.*?)/'); - expect(Modular.prepareToRegex('/home/list/:id/item/:num'), - '/home/list/(.*?)/item/(.*?)'); - }); - - test('search object ModularRouter to url', () { - var router = - ModularRouter('/home/list/:id', child: (_, __) => SizedBox.shrink()); - - expect( - Modular.searchRoute(router, "/home/list/:id", "/home/list/1"), true); - expect(router.params['id'], "1"); - - expect( - Modular.searchRoute( - router, "/home/list/:id/item/:num", "/home/list/1/item/2"), - true); - expect(router.params['id'], "1"); - expect(router.params['num'], "2"); - - expect( - Modular.searchRoute( - ModularRouter('/home/list', child: (_, __) => SizedBox.shrink()), - "/home/list", - "/home/list/1"), - false); - }); - - test('search object ModularRouter to url String', () { - var router = - ModularRouter('/home/list/:id', child: (_, __) => SizedBox.shrink()); - - expect( - Modular.searchRoute(router, "/home/list/:id", "/home/list/01"), true); - expect(router.params['id'], "01"); - - expect( - Modular.searchRoute( - ModularRouter('/home/list', child: (_, __) => SizedBox.shrink()), - "/home/list", - "/home/list/01"), - false); - }); - - test('router with params get', () { - expect(Modular.selectRoute("/list/1/2"), isA()); - expect(Modular.selectRoute("/home/test"), null); - }); - test('router with params get multiple', () { - var a = Modular.selectRoute("/home/list/1/2"); - expect(a, isA()); - }); - test('router with params get multiple 2 modules', () { - expect(Modular.selectRoute("/home/product/"), isA()); - }); - - test('modulePath', () { - var router = Modular.selectRoute("/home/product/"); - - expect(router, isA()); - expect(router.modulePath, "/home/product"); - - router = Modular.selectRoute("/home/product/1"); - expect(router, isA()); - expect(router.modulePath, "/home/product"); - }); - - test('Convert type', () { - expect(Modular.convertType("value"), isA()); - expect(Modular.convertType("1"), isA()); - expect(Modular.convertType("1.1"), isA()); - expect(Modular.convertType("true"), isA()); - }); - - test('RouteGuard test', () { - expect(() => Modular.selectRoute("/forbidden"), - throwsA(isA())); - }); - test('RouteGuard other module', () { - expect(() => Modular.selectRoute("/home/forbidden2"), - throwsA(isA())); - }); - test('RouteGuard other module', () { - expect(() => Modular.selectRoute("/home/forbidden2"), - throwsA(isA())); - }); - - test('RouteGuard other module Two', () { - expect(() => Modular.selectRoute("/homeTwo/forbidden2"), - throwsA(isA())); - }); - - test('Get route correct', () { - final router = Modular.selectRoute("/prod/product"); - expect(router.routerName, "/product"); - }); - }); -} +// import 'package:flutter/widgets.dart'; +// import 'package:flutter_modular/flutter_modular.dart'; +// import 'package:flutter_test/flutter_test.dart'; + +// import 'app/app_module.dart'; + +// void main() { +// setUpAll(() { +// Modular.init(AppModule()); +// }); + +// group("Group router", () { +// test('Test Get ModularRouter', () { +// expect(Modular.selectRoute("/"), isA()); +// }); +// test('Test Get module ModularRouter', () { +// expect(Modular.selectRoute("home/"), isA()); +// expect(Modular.selectRoute("/home/"), isA()); +// var router = Modular.selectRoute("/home"); +// expect(router.routerName, '/'); +// }); + +// test('router empty', () { +// expect(() => Modular.selectRoute(""), throwsException); +// }); + +// test('prepare to regex', () { +// expect(Modular.prepareToRegex('/home/list/:id'), '/home/list/(.*?)'); +// expect(Modular.prepareToRegex('/home/list/:id/'), '/home/list/(.*?)/'); +// expect(Modular.prepareToRegex('/home/list/:id/item/:num'), +// '/home/list/(.*?)/item/(.*?)'); +// }); + +// test('search object ModularRouter to url', () { +// var router = +// ModularRouter('/home/list/:id', child: (_, __) => SizedBox.shrink()); + +// expect( +// Modular.searchRoute(router, "/home/list/:id", "/home/list/1"), true); +// expect(router.params['id'], "1"); + +// expect( +// Modular.searchRoute( +// router, "/home/list/:id/item/:num", "/home/list/1/item/2"), +// true); +// expect(router.params['id'], "1"); +// expect(router.params['num'], "2"); + +// expect( +// Modular.searchRoute( +// ModularRouter('/home/list', child: (_, __) => SizedBox.shrink()), +// "/home/list", +// "/home/list/1"), +// false); +// }); + +// test('search object ModularRouter to url String', () { +// var router = +// ModularRouter('/home/list/:id', child: (_, __) => SizedBox.shrink()); + +// expect( +// Modular.searchRoute(router, "/home/list/:id", "/home/list/01"), true); +// expect(router.params['id'], "01"); + +// expect( +// Modular.searchRoute( +// ModularRouter('/home/list', child: (_, __) => SizedBox.shrink()), +// "/home/list", +// "/home/list/01"), +// false); +// }); + +// test('router with params get', () { +// expect(Modular.selectRoute("/list/1/2"), isA()); +// expect(Modular.selectRoute("/home/test"), null); +// }); +// test('router with params get multiple', () { +// var a = Modular.selectRoute("/home/list/1/2"); +// expect(a, isA()); +// }); +// test('router with params get multiple 2 modules', () { +// expect(Modular.selectRoute("/home/product/"), isA()); +// }); + +// test('modulePath', () { +// var router = Modular.selectRoute("/home/product/"); + +// expect(router, isA()); +// expect(router.modulePath, "/home/product"); + +// router = Modular.selectRoute("/home/product/1"); +// expect(router, isA()); +// expect(router.modulePath, "/home/product"); +// }); + +// test('Convert type', () { +// expect(Modular.convertType("value"), isA()); +// expect(Modular.convertType("1"), isA()); +// expect(Modular.convertType("1.1"), isA()); +// expect(Modular.convertType("true"), isA()); +// }); + +// test('RouteGuard test', () { +// expect(() => Modular.selectRoute("/forbidden"), +// throwsA(isA())); +// }); +// test('RouteGuard other module', () { +// expect(() => Modular.selectRoute("/home/forbidden2"), +// throwsA(isA())); +// }); +// test('RouteGuard other module', () { +// expect(() => Modular.selectRoute("/home/forbidden2"), +// throwsA(isA())); +// }); + +// test('RouteGuard other module Two', () { +// expect(() => Modular.selectRoute("/homeTwo/forbidden2"), +// throwsA(isA())); +// }); + +// test('Get route correct', () { +// final router = Modular.selectRoute("/prod/product"); +// expect(router.routerName, "/product"); +// }); +// }); +// } diff --git a/flutter_modular/test/modular_test_test.dart b/flutter_modular/test/modular_test_test.dart index dd1effc3..fadf23a8 100644 --- a/flutter_modular/test/modular_test_test.dart +++ b/flutter_modular/test/modular_test_test.dart @@ -21,7 +21,7 @@ void main() { expect(Modular.get(), isA()); }); tearDown(() { - Modular.removeModule(app); + // Modular.removeModule(app); }); }); group("navigation test", () { @@ -38,9 +38,9 @@ void main() { expect(Modular.link.path, '/prod'); }); tearDown(() { - Modular.removeModule(product); - Modular.removeModule(home); - Modular.removeModule(app); + // Modular.removeModule(product); + // Modular.removeModule(home); + // Modular.removeModule(app); }); }); group("arguments test", () { @@ -57,14 +57,14 @@ void main() { expect(titleFinder, findsOneWidget); }); testWidgets("Modular Arguments Page id", (tester) async { - Modular.arguments(data: 10); + // Modular.arguments(data: 10); await tester.pumpWidget(buildTestableWidget(ModularArgumentsPage())); final titleFinder = find.text("10"); expect(titleFinder, findsOneWidget); }); tearDownAll(() { - Modular.removeModule(home); - Modular.removeModule(app); + // Modular.removeModule(home); + // Modular.removeModule(app); }); }); } diff --git a/flutter_modular/test/new_route_test.dart b/flutter_modular/test/new_route_test.dart new file mode 100644 index 00000000..f9eea527 --- /dev/null +++ b/flutter_modular/test/new_route_test.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/delegates/modular_route_path.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_modular/flutter_modular.dart'; + +main() { + test('check initial route', () {}); + + testWidgets('Button is present and triggers navigation after tapped', + (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData.dark(), + ).modular()); + + routerDelegate.handleBookTapped(); + //how to test navigator? + + await tester.pump(); + await tester.pumpAndSettle(); + Modular.to.pop(); + await tester.pump(); + }); +} From fcba34b3a1b79aa2641999dd7f2744e4e4016173 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 24 Oct 2020 11:55:13 -0300 Subject: [PATCH 06/71] configure delegates --- .../modular_route_information_parser.dart | 146 ++++++++++++++++-- .../delegates/modular_router_delegate.dart | 80 ++++++---- .../lib/src/interfaces/modular_interface.dart | 4 + flutter_modular/lib/src/modular_base.dart | 28 ++-- flutter_modular/lib/src/modular_impl.dart | 42 ++++- .../navigator/modular_navigator_outlet.dart | 26 ++-- .../lib/src/routers/modular_navigator.dart | 108 +------------ .../lib/src/routers/modular_page.dart | 13 ++ .../lib/src/routers/modular_router.dart | 59 +++++-- .../lib/src/utils/modular_arguments.dart | 7 +- .../lib/src/widgets/modular_app.dart | 2 +- flutter_modular/pubspec.yaml | 2 +- flutter_modular/test/app/app_module.dart | 7 +- flutter_modular/test/app/app_widget.dart | 13 +- .../test/app/modules/home/home_module.dart | 24 +-- flutter_modular/test/new_route_test.dart | 25 +-- 16 files changed, 350 insertions(+), 236 deletions(-) create mode 100644 flutter_modular/lib/src/routers/modular_page.dart diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart index 5881dbbb..de9023d4 100644 --- a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart @@ -1,30 +1,146 @@ import 'package:flutter/material.dart'; -import 'modular_route_path.dart'; +import '../../flutter_modular.dart'; class ModularRouteInformationParser - extends RouteInformationParser { + extends RouteInformationParser { @override - Future parseRouteInformation( + Future parseRouteInformation( RouteInformation routeInformation) async { - final uri = Uri.parse(routeInformation.location); + final path = routeInformation.location; + final route = selectRoute(path); + return route; + } + + @override + RouteInformation restoreRouteInformation(ModularRouter router) { + return RouteInformation(location: router.path); + } + + ModularRouter _searchInModule( + ChildModule module, String routerName, String path) { + path = "/$path".replaceAll('//', '/'); + final routers = + module.routers.map((e) => e.copyWith(currentModule: module)).toList(); + routers.sort((preview, actual) { + return preview.routerName.contains('/:') ? 1 : 0; + }); + for (var route in routers) { + route = _searchRoute(route, routerName, path); + if (route != null) { + return route; + } + } + return null; + } + + ModularRouter _searchRoute( + ModularRouter route, String routerName, String path) { + final tempRouteName = + (routerName + route.routerName).replaceFirst('//', '/'); + if (route.child == null) { + var _routerName = + ('$routerName${route.routerName}/').replaceFirst('//', '/'); + ModularRouter router; + if (_routerName == path || _routerName == "$path/") { + router = route.module.routers[0]; + if (router.module != null) { + var _routerName = + (routerName + route.routerName).replaceFirst('//', '/'); + router = _searchInModule(route.module, _routerName, path); + } + } else { + router = _searchInModule(route.module, _routerName, path); + } - if (uri.pathSegments.length >= 2) { - var remaining = uri.pathSegments[1]; - return BookRoutePath.details(int.tryParse(remaining)); + if (router != null) { + router = router.copyWith( + modulePath: router.modulePath == null ? '/' : tempRouteName, + path: path, + ); + + if (router.transition == TransitionType.defaultTransition) { + router = router.copyWith( + transition: route.transition, + customTransition: route.customTransition, + ); + } + Modular.bindModule(route.module, path); + return router; + } } else { - return BookRoutePath.home(); + if (_parseUrlParams(route, tempRouteName, path)) { + Modular.bindModule(route.currentModule, path); + return route.copyWith(path: path); + } } + + return null; } - @override - RouteInformation restoreRouteInformation(BookRoutePath path) { - if (path.isHomePage) { - return RouteInformation(location: '/'); + String prepareToRegex(String url) { + final newUrl = []; + for (var part in url.split('/')) { + var url = part.contains(":") ? "(.*?)" : part; + newUrl.add(url); + } + + return newUrl.join("/"); + } + + bool _parseUrlParams(ModularRouter router, String routeNamed, String path) { + if (routeNamed.split('/').length != path.split('/').length) { + return false; + } + + if (routeNamed.contains('/:')) { + final regExp = RegExp( + "^${prepareToRegex(routeNamed)}\$", + caseSensitive: true, + ); + var r = regExp.firstMatch(path); + if (r != null) { + final params = {}; + var paramPos = 0; + final routeParts = routeNamed.split('/'); + final pathParts = path.split('/'); + + // print('Match! Processing $path as $routeNamed'); + + for (var routePart in routeParts) { + if (routePart.contains(":")) { + var paramName = routePart.replaceFirst(':', ''); + if (pathParts[paramPos].isNotEmpty) { + params[paramName] = pathParts[paramPos]; + routeNamed = + routeNamed.replaceFirst(routePart, params[paramName]); + } + } + paramPos++; + } + + // print('Result processed $path as $routeNamed'); + + if (routeNamed != path) { + router.args = router.args.copyWith(params: null); + return false; + } + router.args = router.args.copyWith(params: params); + return true; + } + + router.args = router.args.copyWith(params: null); + return false; } - if (path.isDetailsPage) { - return RouteInformation(location: '/book/${path.id}'); + + return routeNamed == path; + } + + ModularRouter selectRoute(String path, [ChildModule module]) { + if (path.isEmpty) { + throw Exception("Router can not be empty"); } - return null; + final route = _searchInModule(module ?? Modular.initialModule, "", path); + return route; } } diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index 8051198d..c848d964 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -1,56 +1,84 @@ import 'package:flutter/material.dart'; +import 'package:flutter_modular/flutter_modular.dart'; +import 'package:flutter_modular/src/routers/modular_page.dart'; +import 'modular_route_information_parser.dart'; import 'modular_route_path.dart'; import 'transitionDelegate.dart'; -class ModularRouterDelegate extends RouterDelegate - with ChangeNotifier, PopNavigatorRouterDelegateMixin { +final List _routers = []; + +class ModularRouterDelegate extends RouterDelegate + with ChangeNotifier, PopNavigatorRouterDelegateMixin { final GlobalKey navigatorKey; + final ModularRouteInformationParser parser; + final Map injectMap; - ModularRouterDelegate(this.navigatorKey); + TransitionDelegate transitionDelegate = NoAnimationTransitionDelegate(); - int counter = 0; + ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); @override - BookRoutePath get currentConfiguration => - counter == 0 ? BookRoutePath.home() : BookRoutePath.home(); + ModularRouter get currentConfiguration => _routers.last; @override Widget build(BuildContext context) { + if (_routers.isEmpty) { + _routers.add(parser.selectRoute(Modular.initialRoute)); + } + return Navigator( key: navigatorKey, - transitionDelegate: NoAnimationTransitionDelegate(), - pages: [ - MaterialPage( - key: ValueKey('BooksListPage'), - child: Scaffold(), - ), - if (counter > 0) - MaterialPage( - key: ValueKey('BooksListPage2'), - child: Scaffold(), - ), - ], + transitionDelegate: transitionDelegate, + pages: _routers.map((router) => ModularPage(router)).toList(), onPopPage: (route, result) { if (!route.didPop(result)) { return false; } + final path = _routers.last.path; + _routers.removeLast(); + notifyListeners(); + + final trash = []; + + injectMap.forEach((key, module) { + module.paths.remove(path); + if (module.paths.length == 0) { + module.cleanInjects(); + trash.add(key); + Modular.debugPrintModular( + "-- ${module.runtimeType.toString()} DISPOSED"); + } + }); + + for (final key in trash) { + injectMap.remove(key); + } + return true; }, ); } @override - Future setNewRoutePath(BookRoutePath path) async { - if (path?.isDetailsPage == true) { - counter = 2; - print(path?.id); + Future setNewRoutePath(ModularRouter router) async { + if (Modular.initialRoute != router.path) { + transitionDelegate = DefaultTransitionDelegate(); + final index = _routers.indexOf(router); + if (index == -1) { + _routers.add(router); + } else { + _routers[index] = router; + transitionDelegate = NoAnimationTransitionDelegate(); + } + + notifyListeners(); } } - void handleBookTapped() { - // _selectedBook = book; - counter = 2; - notifyListeners(); + Future pushNamed(String path, {Object arguments}) async { + final router = parser.selectRoute(path); + setNewRoutePath( + router.copyWith(args: router?.args?.copyWith(data: arguments))); } } diff --git a/flutter_modular/lib/src/interfaces/modular_interface.dart b/flutter_modular/lib/src/interfaces/modular_interface.dart index df22ef34..15c128a2 100644 --- a/flutter_modular/lib/src/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_interface.dart @@ -5,6 +5,10 @@ abstract class ModularInterface { String get initialRoute; IModularNavigator get navigatorDelegate; + ChildModule get initialModule; + void init(ChildModule module); + void bindModule(ChildModule module, [String path]); + void debugPrintModular(String text); IModularNavigator get to; IModularNavigator get link; diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index 782ed2fe..049996a7 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../flutter_modular.dart'; @@ -6,21 +5,24 @@ import 'delegates/modular_route_information_parser.dart'; import 'delegates/modular_router_delegate.dart'; import 'interfaces/child_module.dart'; import 'interfaces/modular_interface.dart'; -import 'interfaces/route_guard.dart'; import 'modular_impl.dart'; -import 'routers/modular_navigator.dart'; -import 'routers/modular_router.dart'; -import 'utils/modular_arguments.dart'; -import 'utils/old.dart'; final _navigatorKey = GlobalKey(); +final Map _injectMap = {}; + final routeInformationParser = ModularRouteInformationParser(); -final routerDelegate = ModularRouterDelegate(_navigatorKey); -const Map _injectMap = {}; +final routerDelegate = ModularRouterDelegate( + _navigatorKey, + routeInformationParser, + _injectMap, +); + // ignore: non_constant_identifier_names -final ModularInterface Modular = - ModularImpl(routerDelegate: routerDelegate, injectMap: _injectMap); +final ModularInterface Modular = ModularImpl( + routerDelegate: routerDelegate, + injectMap: _injectMap, +); extension ModularExtension on MaterialApp { MaterialApp modular() { @@ -60,12 +62,6 @@ extension ModularExtension on MaterialApp { } } -_debugPrintModular(String text) { - if (Modular.debugMode) { - debugPrint(text); - } -} - // class _Modular { // static ChildModule _initialModule; // static ModularArguments _args; diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index 63bdd558..b87d8396 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -5,18 +5,54 @@ import 'delegates/modular_router_delegate.dart'; import 'interfaces/modular_interface.dart'; import 'routers/modular_navigator.dart'; +ChildModule _initialModule; + class ModularImpl implements ModularInterface { final ModularRouterDelegate routerDelegate; final Map injectMap; final IModularNavigator navigatorDelegate; - const ModularImpl( - {this.routerDelegate, this.injectMap, this.navigatorDelegate}); + const ModularImpl({ + this.routerDelegate, + this.injectMap, + this.navigatorDelegate, + }); + + @override + ChildModule get initialModule => _initialModule; + + @override + void debugPrintModular(String text) { + if (Modular.debugMode) { + debugPrint(text); + } + } + + @override + void bindModule(ChildModule module, [String path]) { + assert(module != null); + final name = module.runtimeType.toString(); + if (!injectMap.containsKey(name)) { + module.paths.add(path); + injectMap[name] = module; + module.instance(); + debugPrintModular("-- ${module.runtimeType.toString()} INITIALIZED"); + } else { + injectMap[name].paths.add(path); + } + } + + @override + void init(ChildModule module) { + _initialModule = module; + bindModule(module, "global=="); + } @override IModularNavigator get to { return navigatorDelegate ?? - ModularNavigator(routerDelegate.navigatorKey.currentState); + ModularNavigator( + routerDelegate.navigatorKey.currentState, routerDelegate); } @override diff --git a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart b/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart index 3b1143fd..c3ead773 100644 --- a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart +++ b/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart @@ -2,17 +2,17 @@ import 'package:flutter/widgets.dart'; import '../routers/modular_navigator.dart'; -class ModularNavigatorOutlet extends ModularNavigator { - final NavigatorState global; - final NavigatorState module; - ModularNavigatorOutlet({this.module, this.global}) : super(module); +// class ModularNavigatorOutlet extends ModularNavigator { +// final NavigatorState global; +// final NavigatorState module; +// ModularNavigatorOutlet({this.module, this.global}) : super(module); - @override - void pop([T result]) { - if (module.canPop()) { - module.pop(); - } else { - global.pop(); - } - } -} +// @override +// void pop([T result]) { +// if (module.canPop()) { +// module.pop(); +// } else { +// global.pop(); +// } +// } +// } diff --git a/flutter_modular/lib/src/routers/modular_navigator.dart b/flutter_modular/lib/src/routers/modular_navigator.dart index ab3bc5d1..0a8fa648 100644 --- a/flutter_modular/lib/src/routers/modular_navigator.dart +++ b/flutter_modular/lib/src/routers/modular_navigator.dart @@ -1,51 +1,14 @@ import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/delegates/modular_router_delegate.dart'; import '../../flutter_modular.dart'; import '../interfaces/modular_navigator_interface.dart'; class ModularNavigator implements IModularNavigator { final NavigatorState navigator; + final ModularRouterDelegate routerDelegate; - ModularNavigator(this.navigator); - - @override - Future showDialog({ - @deprecated Widget child, - @required WidgetBuilder builder, - bool barrierDismissible = true, - }) { - return navigator.push(DialogRoute( - pageBuilder: (buildContext, animation, secondaryAnimation) { - final pageChild = child ?? Builder(builder: builder); - return SafeArea( - child: Builder(builder: (context) { - return pageChild; - }), - ); - }, - barrierDismissible: barrierDismissible, - //MaterialLocalizations.of(context).modalBarrierDismissLabel, - barrierLabel: "barier-label", - barrierColor: Colors.black54, - transitionDuration: const Duration(milliseconds: 150), - transitionBuilder: _buildMaterialDialogTransitions, - )); - } - - Widget _buildMaterialDialogTransitions( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - Widget child, - ) { - return FadeTransition( - opacity: CurvedAnimation( - parent: animation, - curve: Curves.easeOut, - ), - child: child, - ); - } + ModularNavigator(this.navigator, this.routerDelegate); @override bool canPop() => navigator.canPop(); @@ -77,7 +40,7 @@ class ModularNavigator implements IModularNavigator { @override Future pushNamed(String routeName, {Object arguments}) => - navigator.pushNamed(routeName, arguments: arguments); + routerDelegate.pushNamed(routeName, arguments: arguments); @override Future pushNamedAndRemoveUntil( @@ -106,66 +69,3 @@ class ModularNavigator implements IModularNavigator { @override String get path => Modular.link.path; } - -class DialogRoute extends PopupRoute { - DialogRoute({ - @required RoutePageBuilder pageBuilder, - bool barrierDismissible = true, - String barrierLabel, - Color barrierColor = const Color(0x80000000), - Duration transitionDuration = const Duration(milliseconds: 200), - RouteTransitionsBuilder transitionBuilder, - RouteSettings settings, - }) : assert(barrierDismissible != null), - _pageBuilder = pageBuilder, - _barrierDismissible = barrierDismissible, - _barrierLabel = barrierLabel, - _barrierColor = barrierColor, - _transitionDuration = transitionDuration, - _transitionBuilder = transitionBuilder, - super(settings: settings); - - final RoutePageBuilder _pageBuilder; - - @override - bool get barrierDismissible => _barrierDismissible; - final bool _barrierDismissible; - - @override - String get barrierLabel => _barrierLabel; - final String _barrierLabel; - - @override - Color get barrierColor => _barrierColor; - final Color _barrierColor; - - @override - Duration get transitionDuration => _transitionDuration; - final Duration _transitionDuration; - - final RouteTransitionsBuilder _transitionBuilder; - - @override - Widget buildPage(BuildContext context, Animation animation, - Animation secondaryAnimation) { - return Semantics( - child: _pageBuilder(context, animation, secondaryAnimation), - scopesRoute: true, - explicitChildNodes: true, - ); - } - - @override - Widget buildTransitions(BuildContext context, Animation animation, - Animation secondaryAnimation, Widget child) { - if (_transitionBuilder == null) { - return FadeTransition( - opacity: CurvedAnimation( - parent: animation, - curve: Curves.linear, - ), - child: child); - } // Some default transition - return _transitionBuilder(context, animation, secondaryAnimation, child); - } -} diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/lib/src/routers/modular_page.dart new file mode 100644 index 00000000..0d8b29de --- /dev/null +++ b/flutter_modular/lib/src/routers/modular_page.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import '../../flutter_modular.dart'; + +class ModularPage extends Page { + final ModularRouter router; + + ModularPage(this.router) : super(key: ValueKey(router.path)); + + @override + Route createRoute(BuildContext context) { + return router.getPageRoute(this); + } +} diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index a4c70eb1..6b2d37f1 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -1,10 +1,12 @@ import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/utils/modular_arguments.dart'; + import '../../flutter_modular.dart'; import '../interfaces/child_module.dart'; import '../interfaces/route_guard.dart'; import '../transitions/transitions.dart'; +import '../utils/modular_arguments.dart'; import '../utils/old.dart'; typedef RouteBuilder = MaterialPageRoute Function( @@ -17,6 +19,12 @@ _debugPrintModular(String text) { } class ModularRouter { + final ChildModule currentModule; + + ModularArguments args = ModularArguments(); + + final String path; + /// /// Paramenter name: [routerName] /// @@ -177,15 +185,18 @@ class ModularRouter { ModularRouter( this.routerName, { + this.path = '/', + this.args = const ModularArguments(), this.module, this.child, this.guards, this.params, + this.currentModule, this.transition = TransitionType.defaultTransition, this.routeGenerator, this.customTransition, this.duration = const Duration(milliseconds: 300), - this.modulePath, + this.modulePath = '/', }) { assert(routerName != null); @@ -226,19 +237,25 @@ class ModularRouter { {Widget Function(BuildContext context, ModularArguments args) child, String routerName, ChildModule module, + ChildModule currentModule, Map params, List guards, TransitionType transition, RouteBuilder routeGenerator, String modulePath, + String path, String duration, + ModularArguments args, CustomTransition customTransition}) { return ModularRouter( routerName ?? this.routerName, child: child ?? this.child, + args: args ?? this.args, module: module ?? this.module, + currentModule: currentModule ?? this.currentModule, params: params ?? this.params, modulePath: modulePath ?? this.modulePath, + path: path ?? this.path, guards: guards ?? this.guards, duration: duration ?? this.duration, routeGenerator: routeGenerator ?? this.routeGenerator, @@ -295,19 +312,17 @@ class ModularRouter { return page; } - Route getPageRoute( - {Map injectMap, - RouteSettings settings, - bool isRouterOutlet}) { - final disposablePage = _disposableGenerate( - injectMap: injectMap, - path: settings.name, - isRouterOutlet: isRouterOutlet); + Route getPageRoute(RouteSettings settings) { + // final disposablePage = _disposableGenerate( + // injectMap: injectMap, + // path: settings.name, + // isRouterOutlet: isRouterOutlet); if (transition == TransitionType.custom && customTransition != null) { return PageRouteBuilder( pageBuilder: (context, _, __) { - return disposablePage; + //return disposablePage; + return child(context, args); }, settings: settings, transitionsBuilder: customTransition.transitionBuilder, @@ -316,7 +331,8 @@ class ModularRouter { } else if (transition == TransitionType.defaultTransition) { // Helper function Widget widgetBuilder(BuildContext context) { - return disposablePage; + //return disposablePage; + return child(context, args); } if (routeGenerator != null) { @@ -328,11 +344,24 @@ class ModularRouter { ); } else { var selectTransition = _transitions[transition]; - return selectTransition((context, args) { - return disposablePage; - }, null, duration, settings); + return selectTransition(child, null, duration, settings); } } + + @override + bool operator ==(Object o) { + if (identical(this, o)) return true; + + return o is ModularRouter && + o.modulePath == modulePath && + o.routerName == routerName && + o.module == module; + } + + @override + int get hashCode { + return currentModule.hashCode ^ routerName.hashCode; + } } enum TransitionType { diff --git a/flutter_modular/lib/src/utils/modular_arguments.dart b/flutter_modular/lib/src/utils/modular_arguments.dart index fbda1385..6307fad5 100644 --- a/flutter_modular/lib/src/utils/modular_arguments.dart +++ b/flutter_modular/lib/src/utils/modular_arguments.dart @@ -2,9 +2,10 @@ class ModularArguments { final Map params; final dynamic data; - ModularArguments(this.params, this.data); + const ModularArguments({this.params, this.data}); - ModularArguments copy() { - return ModularArguments(params, data); + ModularArguments copyWith({Map params, dynamic data}) { + return ModularArguments( + params: params ?? this.params, data: data ?? this.data); } } diff --git a/flutter_modular/lib/src/widgets/modular_app.dart b/flutter_modular/lib/src/widgets/modular_app.dart index 312de05f..32194af0 100644 --- a/flutter_modular/lib/src/widgets/modular_app.dart +++ b/flutter_modular/lib/src/widgets/modular_app.dart @@ -18,7 +18,7 @@ class _ModularAppState extends State { @override void initState() { super.initState(); - // Modular.init(widget.module); + Modular.init(widget.module); } @override diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index b3c19b2e..ac364ddf 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 2.1.0 +version: 2.0.0 homepage: https://github.com/Flutterando/modular environment: diff --git a/flutter_modular/test/app/app_module.dart b/flutter_modular/test/app/app_module.dart index 0eee20a6..d41045fb 100644 --- a/flutter_modular/test/app/app_module.dart +++ b/flutter_modular/test/app/app_module.dart @@ -22,7 +22,6 @@ class AppModule extends MainModule { ModularRouter( "/forbidden", child: (_, args) => ForbiddenWidget(), - guards: [MyGuard()], transition: TransitionType.fadeIn, ), ModularRouter( @@ -30,9 +29,9 @@ class AppModule extends MainModule { module: HomeModule(), transition: TransitionType.fadeIn, ), - ModularRouter("/home", module: HomeModule()), - ModularRouter("/prod", module: ProductModule()), - ModularRouter("/homeTwo", module: HomeModule(), guards: [MyGuard()]), + // ModularRouter("/home", module: HomeModule()), + // ModularRouter("/prod", module: ProductModule()), + // ModularRouter("/homeTwo", module: HomeModule(), guards: [MyGuard()]), ]; @override diff --git a/flutter_modular/test/app/app_widget.dart b/flutter_modular/test/app/app_widget.dart index 380d5966..2f637fa5 100644 --- a/flutter_modular/test/app/app_widget.dart +++ b/flutter_modular/test/app/app_widget.dart @@ -5,16 +5,7 @@ class AppWidget extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - initialRoute: "/", - // onGenerateRoute: Modular.generateRoute, - onUnknownRoute: (context) { - return MaterialPageRoute( - builder: (context) => Scaffold( - appBar: AppBar( - title: Text('Página não encontrada'), - ), - )); - }, - ); + theme: ThemeData.dark(), + ).modular(); } } diff --git a/flutter_modular/test/app/modules/home/home_module.dart b/flutter_modular/test/app/modules/home/home_module.dart index 46c8e723..f0396189 100644 --- a/flutter_modular/test/app/modules/home/home_module.dart +++ b/flutter_modular/test/app/modules/home/home_module.dart @@ -24,18 +24,18 @@ class HomeModule extends ChildModule { child: (_, args) => HomeWidget(), transition: TransitionType.fadeIn, ), - ModularRouter( - "/forbidden2", - child: (_, args) => ForbiddenWidget(), - transition: TransitionType.fadeIn, - guards: [MyGuard()], - ), - ModularRouter("/list/:id/:id2", child: (_, args) => HomeWidget()), - ModularRouter("/product", module: ProductModule()), - ModularRouter("/arguments", - child: (_, args) => ArgumentsPage(id: args.data)), - ModularRouter("/modularArguments", - child: (_, args) => ModularArgumentsPage()), + // ModularRouter( + // "/forbidden2", + // child: (_, args) => ForbiddenWidget(), + // transition: TransitionType.fadeIn, + // guards: [MyGuard()], + // ), + // ModularRouter("/list/:id/:id2", child: (_, args) => HomeWidget()), + // ModularRouter("/product", module: ProductModule()), + // ModularRouter("/arguments", + // child: (_, args) => ArgumentsPage(id: args.data)), + // ModularRouter("/modularArguments", + // child: (_, args) => ModularArgumentsPage()), ]; } diff --git a/flutter_modular/test/new_route_test.dart b/flutter_modular/test/new_route_test.dart index f9eea527..af585ef7 100644 --- a/flutter_modular/test/new_route_test.dart +++ b/flutter_modular/test/new_route_test.dart @@ -3,21 +3,22 @@ import 'package:flutter_modular/src/delegates/modular_route_path.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_modular/flutter_modular.dart'; -main() { - test('check initial route', () {}); +import 'app/app_module.dart'; +main() { testWidgets('Button is present and triggers navigation after tapped', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp( - theme: ThemeData.dark(), - ).modular()); - - routerDelegate.handleBookTapped(); - //how to test navigator? + await tester.runAsync(() async { + await tester.pumpWidget(ModularApp( + module: AppModule(), + )); - await tester.pump(); - await tester.pumpAndSettle(); - Modular.to.pop(); - await tester.pump(); + await routerDelegate.pushNamed('/forbidden'); + await tester.pump(); + //how to test navigator? + await Future.delayed(Duration(seconds: 2)); + Modular.to.pop('Teste pop'); + await tester.pump(); + }); }); } From 2ff4824fcf949dace250223a495aa67cda217635 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 24 Oct 2020 17:12:14 -0300 Subject: [PATCH 07/71] refactor select router --- .../modular_route_information_parser.dart | 28 ++++---- .../lib/src/delegates/modular_route_path.dart | 11 ---- .../delegates/modular_router_delegate.dart | 64 ++++++++++--------- .../lib/src/interfaces/modular_interface.dart | 1 - flutter_modular/lib/src/modular_impl.dart | 20 +++--- 5 files changed, 62 insertions(+), 62 deletions(-) delete mode 100644 flutter_modular/lib/src/delegates/modular_route_path.dart diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart index de9023d4..65dce9da 100644 --- a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart @@ -34,6 +34,22 @@ class ModularRouteInformationParser return null; } + ModularRouter _normalizeRoute( + ModularRouter route, String routerName, String path) { + ModularRouter router; + if (routerName == path || routerName == "$path/") { + router = route.module.routers[0]; + if (router.module != null) { + var _routerName = + (routerName + route.routerName).replaceFirst('//', '/'); + router = _searchInModule(route.module, _routerName, path); + } + } else { + router = _searchInModule(route.module, routerName, path); + } + return router; + } + ModularRouter _searchRoute( ModularRouter route, String routerName, String path) { final tempRouteName = @@ -41,17 +57,7 @@ class ModularRouteInformationParser if (route.child == null) { var _routerName = ('$routerName${route.routerName}/').replaceFirst('//', '/'); - ModularRouter router; - if (_routerName == path || _routerName == "$path/") { - router = route.module.routers[0]; - if (router.module != null) { - var _routerName = - (routerName + route.routerName).replaceFirst('//', '/'); - router = _searchInModule(route.module, _routerName, path); - } - } else { - router = _searchInModule(route.module, _routerName, path); - } + var router = _normalizeRoute(route, _routerName, path); if (router != null) { router = router.copyWith( diff --git a/flutter_modular/lib/src/delegates/modular_route_path.dart b/flutter_modular/lib/src/delegates/modular_route_path.dart deleted file mode 100644 index 6e1f0951..00000000 --- a/flutter_modular/lib/src/delegates/modular_route_path.dart +++ /dev/null @@ -1,11 +0,0 @@ -class BookRoutePath { - final int id; - - BookRoutePath.home() : id = null; - - BookRoutePath.details(this.id); - - bool get isHomePage => id == null; - - bool get isDetailsPage => id != null; -} diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index c848d964..cc4cf88a 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -1,15 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/src/routers/modular_page.dart'; +import '../../flutter_modular.dart'; +import '../routers/modular_page.dart'; import 'modular_route_information_parser.dart'; -import 'modular_route_path.dart'; import 'transitionDelegate.dart'; final List _routers = []; class ModularRouterDelegate extends RouterDelegate - with ChangeNotifier, PopNavigatorRouterDelegateMixin { + with + // ignore: prefer_mixin + ChangeNotifier, + PopNavigatorRouterDelegateMixin { final GlobalKey navigatorKey; final ModularRouteInformationParser parser; final Map injectMap; @@ -31,32 +33,7 @@ class ModularRouterDelegate extends RouterDelegate key: navigatorKey, transitionDelegate: transitionDelegate, pages: _routers.map((router) => ModularPage(router)).toList(), - onPopPage: (route, result) { - if (!route.didPop(result)) { - return false; - } - final path = _routers.last.path; - _routers.removeLast(); - notifyListeners(); - - final trash = []; - - injectMap.forEach((key, module) { - module.paths.remove(path); - if (module.paths.length == 0) { - module.cleanInjects(); - trash.add(key); - Modular.debugPrintModular( - "-- ${module.runtimeType.toString()} DISPOSED"); - } - }); - - for (final key in trash) { - injectMap.remove(key); - } - - return true; - }, + onPopPage: _onPopPage, ); } @@ -81,4 +58,31 @@ class ModularRouterDelegate extends RouterDelegate setNewRoutePath( router.copyWith(args: router?.args?.copyWith(data: arguments))); } + + bool _onPopPage(Route route, dynamic result) { + if (!route.didPop(result)) { + return false; + } + final path = _routers.last.path; + _routers.removeLast(); + notifyListeners(); + + final trash = []; + + injectMap.forEach((key, module) { + module.paths.remove(path); + if (module.paths.length == 0) { + module.cleanInjects(); + trash.add(key); + Modular.debugPrintModular( + "-- ${module.runtimeType.toString()} DISPOSED"); + } + }); + + for (final key in trash) { + injectMap.remove(key); + } + + return true; + } } diff --git a/flutter_modular/lib/src/interfaces/modular_interface.dart b/flutter_modular/lib/src/interfaces/modular_interface.dart index 15c128a2..afa1a4ee 100644 --- a/flutter_modular/lib/src/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_interface.dart @@ -4,7 +4,6 @@ abstract class ModularInterface { bool get debugMode; String get initialRoute; - IModularNavigator get navigatorDelegate; ChildModule get initialModule; void init(ChildModule module); void bindModule(ChildModule module, [String path]); diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index b87d8396..ce63dd79 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -10,13 +10,19 @@ ChildModule _initialModule; class ModularImpl implements ModularInterface { final ModularRouterDelegate routerDelegate; final Map injectMap; - final IModularNavigator navigatorDelegate; + IModularNavigator toNavigator; - const ModularImpl({ + ModularImpl({ this.routerDelegate, this.injectMap, - this.navigatorDelegate, - }); + IModularNavigator navigatorDelegate, + }) { + toNavigator = navigatorDelegate ?? + ModularNavigator( + routerDelegate.navigatorKey.currentState, + routerDelegate, + ); + } @override ChildModule get initialModule => _initialModule; @@ -49,11 +55,7 @@ class ModularImpl implements ModularInterface { } @override - IModularNavigator get to { - return navigatorDelegate ?? - ModularNavigator( - routerDelegate.navigatorKey.currentState, routerDelegate); - } + IModularNavigator get to => toNavigator; @override IModularNavigator get link => throw UnimplementedError(); From 6455686734df452c4c913211eb8d76d9f18001d3 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 25 Oct 2020 22:51:42 -0300 Subject: [PATCH 08/71] fix analysis --- flutter_modular/analysis_options.yaml | 1 - .../example/lib/app/app_widget.dart | 6 +- .../modules/tab1/pages/page2/page2_page.dart | 1 - .../modules/tabs/modules/tab1/tab1_page.dart | 1 - .../lib/app/modules/tabs/tabs_module.dart | 1 - flutter_modular/lib/flutter_modular.dart | 1 + .../delegates/modular_router_delegate.dart | 77 +++++++------ .../lib/src/delegates/transitionDelegate.dart | 36 ------ flutter_modular/lib/src/inject/inject.dart | 1 - flutter_modular/lib/src/modular_impl.dart | 6 +- .../navigator/modular_navigator_outlet.dart | 4 +- .../lib/src/routers/modular_navigator.dart | 8 +- .../lib/src/routers/modular_page.dart | 2 +- .../lib/src/routers/modular_router.dart | 104 +++-------------- .../lib/src/transitions/transitions.dart | 1 - flutter_modular/lib/src/utils/old.dart | 9 -- .../lib/src/widgets/module_widget.dart | 105 ------------------ .../lib/src/widgets/widget_module.dart | 2 +- flutter_modular/pubspec.yaml | 2 +- flutter_modular/test/app/app_module.dart | 2 - .../test/app/modules/home/home_module.dart | 3 - flutter_modular/test/modular_test_test.dart | 3 +- flutter_modular/test/new_route_test.dart | 4 +- 23 files changed, 71 insertions(+), 309 deletions(-) delete mode 100644 flutter_modular/lib/src/delegates/transitionDelegate.dart delete mode 100644 flutter_modular/lib/src/utils/old.dart delete mode 100644 flutter_modular/lib/src/widgets/module_widget.dart diff --git a/flutter_modular/analysis_options.yaml b/flutter_modular/analysis_options.yaml index cfa7ff4c..567202d4 100644 --- a/flutter_modular/analysis_options.yaml +++ b/flutter_modular/analysis_options.yaml @@ -1,6 +1,5 @@ include: package:effective_dart/analysis_options.yaml - linter: rules: public_member_api_docs: false diff --git a/flutter_modular/example/lib/app/app_widget.dart b/flutter_modular/example/lib/app/app_widget.dart index bb91c105..1f553ec2 100644 --- a/flutter_modular/example/lib/app/app_widget.dart +++ b/flutter_modular/example/lib/app/app_widget.dart @@ -4,10 +4,6 @@ import 'package:flutter_modular/flutter_modular.dart'; class AppWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - initialRoute: "/", - // navigatorKey: Modular.navigatorKey, - // onGenerateRoute: Modular.generateRoute, - ); + return MaterialApp().modular(); } } diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart index c507783c..82d41096 100644 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart +++ b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; class Page2Page extends StatefulWidget { final String title; diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart index c2d61b23..484c13d2 100644 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart +++ b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; class Tab1Page extends StatefulWidget { final String title; diff --git a/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart b/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart index 9fa70014..203ca7a8 100644 --- a/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart +++ b/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart @@ -1,6 +1,5 @@ import 'package:example/app/modules/tabs/tabs_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; -import 'package:example/app/modules/tabs/tabs_page.dart'; class TabsModule extends ChildModule { @override diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 5e8baa36..fb7ba6c5 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -12,6 +12,7 @@ export 'src/interfaces/route_guard.dart'; export 'src/modular_base.dart'; export 'src/routers/modular_router.dart'; export 'src/routers/route_link.dart'; +export 'src/utils/modular_arguments.dart'; export 'src/widgets/consumer_widget.dart'; export 'src/widgets/modular_app.dart'; export 'src/widgets/modular_stateful_widget_state.dart'; diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index cc4cf88a..8b2197d9 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -3,9 +3,6 @@ import '../../flutter_modular.dart'; import '../routers/modular_page.dart'; import 'modular_route_information_parser.dart'; -import 'transitionDelegate.dart'; - -final List _routers = []; class ModularRouterDelegate extends RouterDelegate with @@ -16,56 +13,65 @@ class ModularRouterDelegate extends RouterDelegate final ModularRouteInformationParser parser; final Map injectMap; - TransitionDelegate transitionDelegate = NoAnimationTransitionDelegate(); - ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); + List _pages = []; + @override - ModularRouter get currentConfiguration => _routers.last; + ModularRouter get currentConfiguration => _pages.last.router; @override Widget build(BuildContext context) { - if (_routers.isEmpty) { - _routers.add(parser.selectRoute(Modular.initialRoute)); - } - - return Navigator( - key: navigatorKey, - transitionDelegate: transitionDelegate, - pages: _routers.map((router) => ModularPage(router)).toList(), - onPopPage: _onPopPage, - ); + return _pages.isEmpty + ? Material() + : Navigator( + key: navigatorKey, + pages: _pages, + onPopPage: _onPopPage, + ); } @override Future setNewRoutePath(ModularRouter router) async { - if (Modular.initialRoute != router.path) { - transitionDelegate = DefaultTransitionDelegate(); - final index = _routers.indexOf(router); - if (index == -1) { - _routers.add(router); - } else { - _routers[index] = router; - transitionDelegate = NoAnimationTransitionDelegate(); - } - - notifyListeners(); + final index = _pages.indexWhere((element) => element.router == router); + final page = ModularPage( + key: ValueKey('url:${router.path}'), + router: router, + ); + if (index == -1) { + _pages.add(page); + } else { + _pages[index] = page; } + + rebuildPages(); } Future pushNamed(String path, {Object arguments}) async { - final router = parser.selectRoute(path); - setNewRoutePath( - router.copyWith(args: router?.args?.copyWith(data: arguments))); + var router = parser.selectRoute(path); + router = router.copyWith(args: router?.args?.copyWith(data: arguments)); + final page = ModularPage( + router: router, + ); + _pages.add(page); + rebuildPages(); + return router.popRoute.future; } bool _onPopPage(Route route, dynamic result) { if (!route.didPop(result)) { return false; } - final path = _routers.last.path; - _routers.removeLast(); - notifyListeners(); + + if (route.isFirst) { + return false; + } + + final page = route.settings as ModularPage; + final path = page.router.path; + page.router.popRoute.complete(result); + _pages.removeLast(); + rebuildPages(); final trash = []; @@ -85,4 +91,9 @@ class ModularRouterDelegate extends RouterDelegate return true; } + + void rebuildPages() { + _pages = List.from(_pages); + notifyListeners(); + } } diff --git a/flutter_modular/lib/src/delegates/transitionDelegate.dart b/flutter_modular/lib/src/delegates/transitionDelegate.dart deleted file mode 100644 index 9c0d7adb..00000000 --- a/flutter_modular/lib/src/delegates/transitionDelegate.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/material.dart'; - -class NoAnimationTransitionDelegate extends TransitionDelegate { - @override - Iterable resolve({ - List newPageRouteHistory, - Map - locationToExitingPageRoute, - Map> - pageRouteToPagelessRoutes, - }) { - final results = []; - - for (final pageRoute in newPageRouteHistory) { - if (pageRoute.isWaitingForEnteringDecision) { - pageRoute.markForAdd(); - } - results.add(pageRoute); - } - - for (final exitingPageRoute in locationToExitingPageRoute.values) { - if (exitingPageRoute.isWaitingForExitingDecision) { - exitingPageRoute.markForRemove(); - final pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute]; - if (pagelessRoutes != null) { - for (final pagelessRoute in pagelessRoutes) { - pagelessRoute.markForRemove(); - } - } - } - - results.add(exitingPageRoute); - } - return results; - } -} diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/lib/src/inject/inject.dart index 1e4ff9b7..cd877c06 100644 --- a/flutter_modular/lib/src/inject/inject.dart +++ b/flutter_modular/lib/src/inject/inject.dart @@ -1,5 +1,4 @@ import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/src/utils/modular_arguments.dart'; import '../../flutter_modular.dart'; import '../modular_base.dart'; diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index ce63dd79..2785a821 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -17,11 +17,7 @@ class ModularImpl implements ModularInterface { this.injectMap, IModularNavigator navigatorDelegate, }) { - toNavigator = navigatorDelegate ?? - ModularNavigator( - routerDelegate.navigatorKey.currentState, - routerDelegate, - ); + toNavigator = navigatorDelegate ?? ModularNavigator(routerDelegate); } @override diff --git a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart b/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart index c3ead773..957d75cb 100644 --- a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart +++ b/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart @@ -1,6 +1,6 @@ -import 'package:flutter/widgets.dart'; +// import 'package:flutter/widgets.dart'; -import '../routers/modular_navigator.dart'; +// import '../routers/modular_navigator.dart'; // class ModularNavigatorOutlet extends ModularNavigator { // final NavigatorState global; diff --git a/flutter_modular/lib/src/routers/modular_navigator.dart b/flutter_modular/lib/src/routers/modular_navigator.dart index 0a8fa648..6cf8b75c 100644 --- a/flutter_modular/lib/src/routers/modular_navigator.dart +++ b/flutter_modular/lib/src/routers/modular_navigator.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/delegates/modular_router_delegate.dart'; - import '../../flutter_modular.dart'; +import '../delegates/modular_router_delegate.dart'; import '../interfaces/modular_navigator_interface.dart'; class ModularNavigator implements IModularNavigator { - final NavigatorState navigator; final ModularRouterDelegate routerDelegate; - ModularNavigator(this.navigator, this.routerDelegate); + ModularNavigator(this.routerDelegate); + + NavigatorState get navigator => routerDelegate.navigatorKey.currentState; @override bool canPop() => navigator.canPop(); diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/lib/src/routers/modular_page.dart index 0d8b29de..34dfc0d8 100644 --- a/flutter_modular/lib/src/routers/modular_page.dart +++ b/flutter_modular/lib/src/routers/modular_page.dart @@ -4,7 +4,7 @@ import '../../flutter_modular.dart'; class ModularPage extends Page { final ModularRouter router; - ModularPage(this.router) : super(key: ValueKey(router.path)); + const ModularPage({Key key, this.router}) : super(key: key); @override Route createRoute(BuildContext context) { diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index 6b2d37f1..39b705b2 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -7,21 +9,16 @@ import '../interfaces/child_module.dart'; import '../interfaces/route_guard.dart'; import '../transitions/transitions.dart'; import '../utils/modular_arguments.dart'; -import '../utils/old.dart'; typedef RouteBuilder = MaterialPageRoute Function( WidgetBuilder, RouteSettings); -_debugPrintModular(String text) { - if (Modular.debugMode) { - debugPrint(text); - } -} - class ModularRouter { final ChildModule currentModule; - ModularArguments args = ModularArguments(); + Completer popRoute = Completer(); + + ModularArguments args; final String path; @@ -195,11 +192,14 @@ class ModularRouter { this.transition = TransitionType.defaultTransition, this.routeGenerator, this.customTransition, + this.popRoute, this.duration = const Duration(milliseconds: 300), this.modulePath = '/', }) { assert(routerName != null); + popRoute = popRoute ?? Completer(); + if (transition == null) throw ArgumentError('transition must not be null'); if (transition == TransitionType.custom && customTransition == null) { throw ArgumentError( @@ -245,6 +245,7 @@ class ModularRouter { String modulePath, String path, String duration, + Completer popRoute, ModularArguments args, CustomTransition customTransition}) { return ModularRouter( @@ -256,6 +257,7 @@ class ModularRouter { params: params ?? this.params, modulePath: modulePath ?? this.modulePath, path: path ?? this.path, + popRoute: popRoute ?? this.popRoute, guards: guards ?? this.guards, duration: duration ?? this.duration, routeGenerator: routeGenerator ?? this.routeGenerator, @@ -279,45 +281,7 @@ class ModularRouter { }).toList(); } - Widget _disposableGenerate({ - Map injectMap, - bool isRouterOutlet, - String path, - }) { - Widget page = _DisposableWidget( - child: child, - dispose: (old, actual) { - final trash = []; - if (!isRouterOutlet) { - // Modular.oldProccess(old); - // Modular.updateCurrentModuleApp(); - } - if (actual.isCurrent) { - return; - } - injectMap.forEach((key, module) { - module.paths.remove(path); - if (module.paths.length == 0) { - module.cleanInjects(); - trash.add(key); - _debugPrintModular("-- ${module.runtimeType.toString()} DISPOSED"); - } - }); - - for (final key in trash) { - injectMap.remove(key); - } - }, - ); - return page; - } - Route getPageRoute(RouteSettings settings) { - // final disposablePage = _disposableGenerate( - // injectMap: injectMap, - // path: settings.name, - // isRouterOutlet: isRouterOutlet); - if (transition == TransitionType.custom && customTransition != null) { return PageRouteBuilder( pageBuilder: (context, _, __) { @@ -344,11 +308,12 @@ class ModularRouter { ); } else { var selectTransition = _transitions[transition]; - return selectTransition(child, null, duration, settings); + return selectTransition(child, args, duration, settings); } } @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes bool operator ==(Object o) { if (identical(this, o)) return true; @@ -359,6 +324,7 @@ class ModularRouter { } @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes int get hashCode { return currentModule.hashCode ^ routerName.hashCode; } @@ -390,47 +356,3 @@ class CustomTransition { {@required this.transitionBuilder, this.transitionDuration = const Duration(milliseconds: 300)}); } - -class _DisposableWidget extends StatefulWidget { - final Function(Old old, ModalRoute actual) dispose; - final Widget Function(BuildContext context, ModularArguments args) child; - - _DisposableWidget({ - Key key, - this.dispose, - this.child, - }) : super(key: key); - - @override - __DisposableWidgetState createState() => __DisposableWidgetState(); -} - -class __DisposableWidgetState extends State<_DisposableWidget> { - Old old; - ModalRoute actual; - ModularArguments args; - - @override - void initState() { - super.initState(); - // old = Modular.old; - // args = Modular.args; - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - actual = ModalRoute.of(context); - } - - @override - void dispose() { - widget.dispose(old, actual); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return widget.child(context, args); - } -} diff --git a/flutter_modular/lib/src/transitions/transitions.dart b/flutter_modular/lib/src/transitions/transitions.dart index cc15ca4d..8ddff6f9 100644 --- a/flutter_modular/lib/src/transitions/transitions.dart +++ b/flutter_modular/lib/src/transitions/transitions.dart @@ -1,5 +1,4 @@ import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/src/utils/modular_arguments.dart'; import '../../flutter_modular.dart'; import 'page_transition.dart'; diff --git a/flutter_modular/lib/src/utils/old.dart b/flutter_modular/lib/src/utils/old.dart deleted file mode 100644 index 0b814ab8..00000000 --- a/flutter_modular/lib/src/utils/old.dart +++ /dev/null @@ -1,9 +0,0 @@ -import '../../flutter_modular.dart'; -import 'modular_arguments.dart'; - -class Old { - final ModularArguments args; - final RouteLink link; - - Old({this.args, this.link}); -} diff --git a/flutter_modular/lib/src/widgets/module_widget.dart b/flutter_modular/lib/src/widgets/module_widget.dart deleted file mode 100644 index 81e847b5..00000000 --- a/flutter_modular/lib/src/widgets/module_widget.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../../flutter_modular.dart'; - -_debugPrintModular(String text) { - if (Modular.debugMode) { - debugPrint(text); - } -} - -abstract class WidgetModule extends StatelessWidget implements ChildModule { - @override - List get binds; - - Widget get view; - - final _FakeModule _fakeModule = _FakeModule(); - - WidgetModule() { - _fakeModule.changeBinds(binds); - } - - @override - void changeBinds(List b) { - _fakeModule.changeBinds(b); - } - - @override - void cleanInjects() { - _fakeModule.cleanInjects(); - } - - @override - T getBind(Map params, {List typesInRequest}) { - return _fakeModule.getBind(params, typesInRequest: typesInRequest); - } - - @override - List get paths => [runtimeType.toString()]; - - @override - bool remove() { - return _fakeModule.remove(); - } - - @override - void instance() { - _fakeModule.instance(); - } - - @override - List get routers => null; - - @override - Widget build(BuildContext context) { - return ModularProvider( - module: this, - child: view, - ); - } -} - -class _FakeModule extends ChildModule { - final List bindsInject; - - _FakeModule({String path, this.bindsInject}) { - paths.add(runtimeType.toString()); - } - - @override - List get binds => bindsInject; - - @override - List get routers => null; -} - -class ModularProvider extends StatefulWidget { - final ChildModule module; - final Widget child; - - const ModularProvider({Key key, this.module, this.child}) : super(key: key); - - @override - _ModularProviderState createState() => _ModularProviderState(); -} - -class _ModularProviderState extends State { - @override - void initState() { - super.initState(); - //Modular.addCoreInit(widget.module); - _debugPrintModular("-- ${widget.module.runtimeType} INITIALIZED"); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } - - @override - void dispose() { - super.dispose(); - //Modular.removeModule(widget.module); - _debugPrintModular("-- ${widget.module.runtimeType} DISPOSED"); - } -} diff --git a/flutter_modular/lib/src/widgets/widget_module.dart b/flutter_modular/lib/src/widgets/widget_module.dart index a51b2dd0..47b4338d 100644 --- a/flutter_modular/lib/src/widgets/widget_module.dart +++ b/flutter_modular/lib/src/widgets/widget_module.dart @@ -62,7 +62,7 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { class _FakeModule extends ChildModule { final List bindsInject; - _FakeModule({String path, this.bindsInject}) { + _FakeModule({this.bindsInject}) { paths.add(runtimeType.toString()); } diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index ac364ddf..ba706bb7 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter dev_dependencies: - effective_dart: 1.2.2 + effective_dart: 1.2.4 mockito: ^4.1.1 flutter_test: sdk: flutter diff --git a/flutter_modular/test/app/app_module.dart b/flutter_modular/test/app/app_module.dart index d41045fb..00cb826a 100644 --- a/flutter_modular/test/app/app_module.dart +++ b/flutter_modular/test/app/app_module.dart @@ -3,10 +3,8 @@ import 'package:flutter_modular/flutter_modular.dart'; import 'app_bloc.dart'; import 'app_widget.dart'; -import 'guard/guard.dart'; import 'modules/forbidden/forbidden_widget.dart'; import 'modules/home/home_module.dart'; -import 'modules/product/product_module.dart'; import 'shared/ilocal_repository.dart'; import 'shared/local_storage_shared.dart'; diff --git a/flutter_modular/test/app/modules/home/home_module.dart b/flutter_modular/test/app/modules/home/home_module.dart index f0396189..b5a5957e 100644 --- a/flutter_modular/test/app/modules/home/home_module.dart +++ b/flutter_modular/test/app/modules/home/home_module.dart @@ -2,10 +2,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_modular/flutter_modular.dart'; import '../../app_bloc.dart'; -import '../../guard/guard.dart'; import '../../shared/app_info.state.dart'; -import '../forbidden/forbidden_widget.dart'; -import '../product/product_module.dart'; import 'home_bloc.dart'; import 'home_widget.dart'; diff --git a/flutter_modular/test/modular_test_test.dart b/flutter_modular/test/modular_test_test.dart index fadf23a8..8c230cea 100644 --- a/flutter_modular/test/modular_test_test.dart +++ b/flutter_modular/test/modular_test_test.dart @@ -11,7 +11,7 @@ import 'app/shared/local_mock.dart'; void main() { group("change bind", () { - final app = AppModule(); + // final app = AppModule(); setUp(() { initModule(AppModule(), changeBinds: [ Bind((i) => LocalMock()), @@ -45,7 +45,6 @@ void main() { }); group("arguments test", () { final app = AppModule(); - final home = HomeModule(); setUpAll(() { initModule(app, initialModule: true); }); diff --git a/flutter_modular/test/new_route_test.dart b/flutter_modular/test/new_route_test.dart index af585ef7..b5db7f9d 100644 --- a/flutter_modular/test/new_route_test.dart +++ b/flutter_modular/test/new_route_test.dart @@ -1,5 +1,3 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/delegates/modular_route_path.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -7,7 +5,7 @@ import 'app/app_module.dart'; main() { testWidgets('Button is present and triggers navigation after tapped', - (WidgetTester tester) async { + (tester) async { await tester.runAsync(() async { await tester.pumpWidget(ModularApp( module: AppModule(), From 7ac0ce8b7f1674da03da347618e862ac4c140f48 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 25 Oct 2020 23:06:16 -0300 Subject: [PATCH 09/71] delete example --- flutter_modular/example/.gitignore | 36 -- flutter_modular/example/.metadata | 10 - flutter_modular/example/.vscode/launch.json | 33 - flutter_modular/example/README.md | 4 - flutter_modular/example/android/.gitignore | 7 - .../example/android/app/build.gradle | 67 -- .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 30 - .../com/example/example/MainActivity.kt | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values/styles.xml | 8 - .../app/src/profile/AndroidManifest.xml | 7 - flutter_modular/example/android/build.gradle | 31 - .../example/android/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.properties | 6 - .../example/android/settings.gradle | 15 - flutter_modular/example/ios/.gitignore | 32 - .../example/ios/Flutter/.last_build_id | 1 - .../ios/Flutter/AppFrameworkInfo.plist | 26 - .../example/ios/Flutter/Debug.xcconfig | 1 - .../example/ios/Flutter/Release.xcconfig | 1 - .../ios/Runner.xcodeproj/project.pbxproj | 503 --------------- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 91 --- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 ---- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- .../ios/Runner/Base.lproj/Main.storyboard | 26 - flutter_modular/example/ios/Runner/Info.plist | 45 -- .../ios/Runner/Runner-Bridging-Header.h | 1 - flutter_modular/example/lib/app/app_bloc.dart | 6 - .../example/lib/app/app_module.dart | 23 - .../example/lib/app/app_widget.dart | 9 - .../lib/app/gentest/test.controller.dart | 12 - .../lib/app/gentest/test.controller.g.dart | 13 - .../lib/app/modules/home/guard/guard.dart | 29 - .../lib/app/modules/home/home_bloc.dart | 10 - .../lib/app/modules/home/home_module.dart | 40 -- .../lib/app/modules/home/home_widget.dart | 48 -- .../modules/home/pages/list/list_widget.dart | 22 - .../shopping/pages/page1/page1_bloc.dart | 7 - .../shopping/pages/page1/page1_page.dart | 27 - .../shopping/pages/page2/page2_bloc.dart | 7 - .../shopping/pages/page2/page2_page.dart | 27 - .../shopping/pages/page3/page3_bloc.dart | 7 - .../shopping/pages/page3/page3_page.dart | 27 - .../app/modules/shopping/shopping_bloc.dart | 7 - .../app/modules/shopping/shopping_module.dart | 23 - .../app/modules/shopping/shopping_page.dart | 41 -- .../modules/tab1/pages/page1/page1_bloc.dart | 7 - .../modules/tab1/pages/page1/page1_page.dart | 27 - .../modules/tab1/pages/page2/page2_bloc.dart | 7 - .../modules/tab1/pages/page2/page2_page.dart | 27 - .../modules/tab1/pages/page3/page3_bloc.dart | 7 - .../modules/tab1/pages/page3/page3_page.dart | 27 - .../modules/tab1/pages/page4/page4_bloc.dart | 7 - .../modules/tab1/pages/page4/page4_page.dart | 27 - .../modules/tabs/modules/tab1/tab1_bloc.dart | 7 - .../tabs/modules/tab1/tab1_module.dart | 67 -- .../modules/tabs/modules/tab1/tab1_page.dart | 25 - .../modules/tabs/modules/tab2/tab2_bloc.dart | 7 - .../tabs/modules/tab2/tab2_module.dart | 15 - .../modules/tabs/modules/tab2/tab2_page.dart | 23 - .../lib/app/modules/tabs/tabs_bloc.dart | 12 - .../lib/app/modules/tabs/tabs_module.dart | 14 - .../lib/app/modules/tabs/tabs_page.dart | 60 -- flutter_modular/example/lib/main.dart | 6 - .../example/lib/main_guardtest.dart | 103 --- flutter_modular/example/macos/.gitignore | 6 - .../macos/Flutter/Flutter-Debug.xcconfig | 1 - .../macos/Flutter/Flutter-Release.xcconfig | 1 - .../Flutter/GeneratedPluginRegistrant.swift | 10 - .../macos/Runner.xcodeproj/project.pbxproj | 596 ------------------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 101 --- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../example/macos/Runner/AppDelegate.swift | 9 - .../AppIcon.appiconset/Contents.json | 68 -- .../AppIcon.appiconset/app_icon_1024.png | Bin 46993 -> 0 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 3276 -> 0 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 1429 -> 0 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 5933 -> 0 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 1243 -> 0 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 14800 -> 0 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 1874 -> 0 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 339 ---------- .../macos/Runner/Configs/AppInfo.xcconfig | 14 - .../macos/Runner/Configs/Debug.xcconfig | 2 - .../macos/Runner/Configs/Release.xcconfig | 2 - .../macos/Runner/Configs/Warnings.xcconfig | 13 - .../macos/Runner/DebugProfile.entitlements | 12 - .../example/macos/Runner/Info.plist | 32 - .../macos/Runner/MainFlutterWindow.swift | 15 - .../example/macos/Runner/Release.entitlements | 8 - flutter_modular/example/pubspec.yaml | 85 --- flutter_modular/example/web/favicon.png | Bin 917 -> 0 bytes .../example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes .../example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes flutter_modular/example/web/index.html | 10 - flutter_modular/example/web/manifest.json | 23 - flutter_modular/lib/flutter_modular.dart | 2 - .../navigator/modular_navigator_outlet.dart | 18 - .../modular_stateful_widget_state.dart | 23 - .../src/widgets/modular_stateless_widget.dart | 7 - 135 files changed, 3542 deletions(-) delete mode 100644 flutter_modular/example/.gitignore delete mode 100644 flutter_modular/example/.metadata delete mode 100644 flutter_modular/example/.vscode/launch.json delete mode 100644 flutter_modular/example/README.md delete mode 100644 flutter_modular/example/android/.gitignore delete mode 100644 flutter_modular/example/android/app/build.gradle delete mode 100644 flutter_modular/example/android/app/src/debug/AndroidManifest.xml delete mode 100644 flutter_modular/example/android/app/src/main/AndroidManifest.xml delete mode 100644 flutter_modular/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt delete mode 100644 flutter_modular/example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 flutter_modular/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 flutter_modular/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 flutter_modular/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 flutter_modular/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 flutter_modular/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 flutter_modular/example/android/app/src/main/res/values/styles.xml delete mode 100644 flutter_modular/example/android/app/src/profile/AndroidManifest.xml delete mode 100644 flutter_modular/example/android/build.gradle delete mode 100644 flutter_modular/example/android/gradle.properties delete mode 100644 flutter_modular/example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 flutter_modular/example/android/settings.gradle delete mode 100644 flutter_modular/example/ios/.gitignore delete mode 100644 flutter_modular/example/ios/Flutter/.last_build_id delete mode 100644 flutter_modular/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 flutter_modular/example/ios/Flutter/Debug.xcconfig delete mode 100644 flutter_modular/example/ios/Flutter/Release.xcconfig delete mode 100644 flutter_modular/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 flutter_modular/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 flutter_modular/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 flutter_modular/example/ios/Runner/AppDelegate.swift delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 flutter_modular/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 flutter_modular/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 flutter_modular/example/ios/Runner/Info.plist delete mode 100644 flutter_modular/example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 flutter_modular/example/lib/app/app_bloc.dart delete mode 100644 flutter_modular/example/lib/app/app_module.dart delete mode 100644 flutter_modular/example/lib/app/app_widget.dart delete mode 100644 flutter_modular/example/lib/app/gentest/test.controller.dart delete mode 100644 flutter_modular/example/lib/app/gentest/test.controller.g.dart delete mode 100644 flutter_modular/example/lib/app/modules/home/guard/guard.dart delete mode 100644 flutter_modular/example/lib/app/modules/home/home_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/home/home_module.dart delete mode 100644 flutter_modular/example/lib/app/modules/home/home_widget.dart delete mode 100644 flutter_modular/example/lib/app/modules/home/pages/list/list_widget.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/shopping_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/shopping_module.dart delete mode 100644 flutter_modular/example/lib/app/modules/shopping/shopping_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_module.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_module.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_page.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/tabs_bloc.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/tabs_module.dart delete mode 100644 flutter_modular/example/lib/app/modules/tabs/tabs_page.dart delete mode 100644 flutter_modular/example/lib/main.dart delete mode 100644 flutter_modular/example/lib/main_guardtest.dart delete mode 100644 flutter_modular/example/macos/.gitignore delete mode 100644 flutter_modular/example/macos/Flutter/Flutter-Debug.xcconfig delete mode 100644 flutter_modular/example/macos/Flutter/Flutter-Release.xcconfig delete mode 100644 flutter_modular/example/macos/Flutter/GeneratedPluginRegistrant.swift delete mode 100644 flutter_modular/example/macos/Runner.xcodeproj/project.pbxproj delete mode 100644 flutter_modular/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 flutter_modular/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 flutter_modular/example/macos/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 flutter_modular/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 flutter_modular/example/macos/Runner/AppDelegate.swift delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png delete mode 100644 flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png delete mode 100644 flutter_modular/example/macos/Runner/Base.lproj/MainMenu.xib delete mode 100644 flutter_modular/example/macos/Runner/Configs/AppInfo.xcconfig delete mode 100644 flutter_modular/example/macos/Runner/Configs/Debug.xcconfig delete mode 100644 flutter_modular/example/macos/Runner/Configs/Release.xcconfig delete mode 100644 flutter_modular/example/macos/Runner/Configs/Warnings.xcconfig delete mode 100644 flutter_modular/example/macos/Runner/DebugProfile.entitlements delete mode 100644 flutter_modular/example/macos/Runner/Info.plist delete mode 100644 flutter_modular/example/macos/Runner/MainFlutterWindow.swift delete mode 100644 flutter_modular/example/macos/Runner/Release.entitlements delete mode 100644 flutter_modular/example/pubspec.yaml delete mode 100644 flutter_modular/example/web/favicon.png delete mode 100644 flutter_modular/example/web/icons/Icon-192.png delete mode 100644 flutter_modular/example/web/icons/Icon-512.png delete mode 100644 flutter_modular/example/web/index.html delete mode 100644 flutter_modular/example/web/manifest.json delete mode 100644 flutter_modular/lib/src/navigator/modular_navigator_outlet.dart delete mode 100644 flutter_modular/lib/src/widgets/modular_stateful_widget_state.dart delete mode 100644 flutter_modular/lib/src/widgets/modular_stateless_widget.dart diff --git a/flutter_modular/example/.gitignore b/flutter_modular/example/.gitignore deleted file mode 100644 index 437cb458..00000000 --- a/flutter_modular/example/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Exceptions to above rules. -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/flutter_modular/example/.metadata b/flutter_modular/example/.metadata deleted file mode 100644 index 33b905fc..00000000 --- a/flutter_modular/example/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: c90d64b619d674bdca955b94058db01906781819 - channel: master - -project_type: app diff --git a/flutter_modular/example/.vscode/launch.json b/flutter_modular/example/.vscode/launch.json deleted file mode 100644 index 7c7d62d2..00000000 --- a/flutter_modular/example/.vscode/launch.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Flutter", - "request": "launch", - "type": "dart" - }, - { - "name": "Guard Test", - "request": "launch", - "args": [ - "-t", - "lib/main_guardtest.dart" - ], - "type": "dart" - }, - { - "name": "Runner", - "request": "launch", - "args": [ - "pub", - "run", - "build_runner", - "build", - ], - "type": "dart" - } - ] -} \ No newline at end of file diff --git a/flutter_modular/example/README.md b/flutter_modular/example/README.md deleted file mode 100644 index 260d59eb..00000000 --- a/flutter_modular/example/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Modular - -Estrutura de projeto inteligente e organizada. - diff --git a/flutter_modular/example/android/.gitignore b/flutter_modular/example/android/.gitignore deleted file mode 100644 index bc2100d8..00000000 --- a/flutter_modular/example/android/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java diff --git a/flutter_modular/example/android/app/build.gradle b/flutter_modular/example/android/app/build.gradle deleted file mode 100644 index 0f6a5e54..00000000 --- a/flutter_modular/example/android/app/build.gradle +++ /dev/null @@ -1,67 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 28 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - lintOptions { - disable 'InvalidPackage' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" - minSdkVersion 16 - targetSdkVersion 28 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} diff --git a/flutter_modular/example/android/app/src/debug/AndroidManifest.xml b/flutter_modular/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index c208884f..00000000 --- a/flutter_modular/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/flutter_modular/example/android/app/src/main/AndroidManifest.xml b/flutter_modular/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 8bc6007d..00000000 --- a/flutter_modular/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - diff --git a/flutter_modular/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/flutter_modular/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index 1656503f..00000000 --- a/flutter_modular/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.example - -import androidx.annotation.NonNull; -import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant - -class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } -} diff --git a/flutter_modular/example/android/app/src/main/res/drawable/launch_background.xml b/flutter_modular/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/flutter_modular/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/flutter_modular/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/flutter_modular/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/flutter_modular/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/flutter_modular/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/flutter_modular/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/flutter_modular/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/flutter_modular/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/flutter_modular/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/flutter_modular/example/android/app/src/main/res/values/styles.xml b/flutter_modular/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 00fa4417..00000000 --- a/flutter_modular/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/flutter_modular/example/android/app/src/profile/AndroidManifest.xml b/flutter_modular/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index c208884f..00000000 --- a/flutter_modular/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/flutter_modular/example/android/build.gradle b/flutter_modular/example/android/build.gradle deleted file mode 100644 index 3100ad2d..00000000 --- a/flutter_modular/example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/flutter_modular/example/android/gradle.properties b/flutter_modular/example/android/gradle.properties deleted file mode 100644 index 38c8d454..00000000 --- a/flutter_modular/example/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/flutter_modular/example/android/gradle/wrapper/gradle-wrapper.properties b/flutter_modular/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 296b146b..00000000 --- a/flutter_modular/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/flutter_modular/example/android/settings.gradle b/flutter_modular/example/android/settings.gradle deleted file mode 100644 index 5a2f14fb..00000000 --- a/flutter_modular/example/android/settings.gradle +++ /dev/null @@ -1,15 +0,0 @@ -include ':app' - -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() - -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} - -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} diff --git a/flutter_modular/example/ios/.gitignore b/flutter_modular/example/ios/.gitignore deleted file mode 100644 index e96ef602..00000000 --- a/flutter_modular/example/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/flutter_modular/example/ios/Flutter/.last_build_id b/flutter_modular/example/ios/Flutter/.last_build_id deleted file mode 100644 index 73bff18a..00000000 --- a/flutter_modular/example/ios/Flutter/.last_build_id +++ /dev/null @@ -1 +0,0 @@ -bc1b2b4cc2d4e1fabe31723cb8370b79 \ No newline at end of file diff --git a/flutter_modular/example/ios/Flutter/AppFrameworkInfo.plist b/flutter_modular/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 6b4c0f78..00000000 --- a/flutter_modular/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/flutter_modular/example/ios/Flutter/Debug.xcconfig b/flutter_modular/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/flutter_modular/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/flutter_modular/example/ios/Flutter/Release.xcconfig b/flutter_modular/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/flutter_modular/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/flutter_modular/example/ios/Runner.xcodeproj/project.pbxproj b/flutter_modular/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 252c7539..00000000 --- a/flutter_modular/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,503 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/flutter_modular/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/flutter_modular/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_modular/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140cf..00000000 --- a/flutter_modular/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_modular/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/flutter_modular/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/flutter_modular/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/flutter_modular/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/flutter_modular/example/ios/Runner/AppDelegate.swift b/flutter_modular/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/flutter_modular/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab..00000000 --- a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/flutter_modular/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/flutter_modular/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/flutter_modular/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/flutter_modular/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_modular/example/ios/Runner/Base.lproj/Main.storyboard b/flutter_modular/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/flutter_modular/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_modular/example/ios/Runner/Info.plist b/flutter_modular/example/ios/Runner/Info.plist deleted file mode 100644 index a060db61..00000000 --- a/flutter_modular/example/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/flutter_modular/example/ios/Runner/Runner-Bridging-Header.h b/flutter_modular/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 7335fdf9..00000000 --- a/flutter_modular/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file diff --git a/flutter_modular/example/lib/app/app_bloc.dart b/flutter_modular/example/lib/app/app_bloc.dart deleted file mode 100644 index 7afcf6ba..00000000 --- a/flutter_modular/example/lib/app/app_bloc.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart' show Disposable; - -class AppBloc extends Disposable { - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/app_module.dart b/flutter_modular/example/lib/app/app_module.dart deleted file mode 100644 index dc44611b..00000000 --- a/flutter_modular/example/lib/app/app_module.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:example/app/modules/shopping/shopping_module.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'app_widget.dart'; - -import 'modules/home/home_module.dart'; -import 'modules/tabs/tabs_module.dart'; - -class AppModule extends MainModule { - @override - List get binds => []; - - @override - List get routers => [ - ModularRouter("/", module: TabsModule()), - ModularRouter("/home", module: HomeModule()), - ModularRouter("/shopping", module: ShoppingModule()) - ]; - - @override - Widget get bootstrap => AppWidget(); -} diff --git a/flutter_modular/example/lib/app/app_widget.dart b/flutter_modular/example/lib/app/app_widget.dart deleted file mode 100644 index 1f553ec2..00000000 --- a/flutter_modular/example/lib/app/app_widget.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -class AppWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp().modular(); - } -} diff --git a/flutter_modular/example/lib/app/gentest/test.controller.dart b/flutter_modular/example/lib/app/gentest/test.controller.dart deleted file mode 100644 index d106a364..00000000 --- a/flutter_modular/example/lib/app/gentest/test.controller.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -import '../app_bloc.dart'; - - -part 'test.controller.g.dart'; - -@Injectable() -class HomeRealController { - final AppBloc bloc; - HomeRealController(this.bloc); -} diff --git a/flutter_modular/example/lib/app/gentest/test.controller.g.dart b/flutter_modular/example/lib/app/gentest/test.controller.g.dart deleted file mode 100644 index 93768306..00000000 --- a/flutter_modular/example/lib/app/gentest/test.controller.g.dart +++ /dev/null @@ -1,13 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'test.controller.dart'; - -// ************************************************************************** -// InjectionGenerator -// ************************************************************************** - -final $HomeRealController = BindInject( - (i) => HomeRealController(i()), - singleton: true, - lazy: true, -); diff --git a/flutter_modular/example/lib/app/modules/home/guard/guard.dart b/flutter_modular/example/lib/app/modules/home/guard/guard.dart deleted file mode 100644 index 6bccaec2..00000000 --- a/flutter_modular/example/lib/app/modules/home/guard/guard.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class LoginExecutor extends GuardExecutor { - final String message; - LoginExecutor({this.message}); - - @override - onGuarded(String path, {bool isActive}) { - if (isActive) { - print('logined and pass'); - return; - } - - print('toast: need login => $message'); - - // Suppose login. - Modular.to.pushNamed('/list/10'); - } -} - -class MyGuard implements RouteGuard { - @override - bool canActivate(String url) { - return url != '/list/2'; - } - - @override - List get executors => [LoginExecutor(message: 'List page')]; -} diff --git a/flutter_modular/example/lib/app/modules/home/home_bloc.dart b/flutter_modular/example/lib/app/modules/home/home_bloc.dart deleted file mode 100644 index 24c3ce19..00000000 --- a/flutter_modular/example/lib/app/modules/home/home_bloc.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/foundation.dart'; - -class HomeBloc extends ChangeNotifier { - int counter = 0; - - increment() { - counter++; - notifyListeners(); - } -} diff --git a/flutter_modular/example/lib/app/modules/home/home_module.dart b/flutter_modular/example/lib/app/modules/home/home_module.dart deleted file mode 100644 index 02ab0e28..00000000 --- a/flutter_modular/example/lib/app/modules/home/home_module.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:example/app/modules/home/pages/list/list_widget.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter/material.dart'; -import 'guard/guard.dart'; -import 'home_bloc.dart'; -import 'home_widget.dart'; - -class SlowerPageRoute extends MaterialPageRoute { - @override - Duration get transitionDuration => Duration(milliseconds: 1200); - - Map eventP; - SlowerPageRoute({ - @required builder, - @required settings, - }) : super(builder: builder, settings: settings); -} - -class HomeModule extends ChildModule { - @override - List get binds => [ - Bind((i) => HomeBloc()), - ]; - - @override - List get routers => [ - ModularRouter( - Modular.initialRoute, - child: (_, args) => HomeWidget(), - ), - ModularRouter( - "/list/:id", - routeGenerator: (b, s) => SlowerPageRoute(builder: b, settings: s), - child: (_, args) => ListWidget( - param: int.parse(args.params['id']), - ), - guards: [MyGuard()], - ), - ]; -} diff --git a/flutter_modular/example/lib/app/modules/home/home_widget.dart b/flutter_modular/example/lib/app/modules/home/home_widget.dart deleted file mode 100644 index dca9f7b3..00000000 --- a/flutter_modular/example/lib/app/modules/home/home_widget.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:example/app/modules/home/home_bloc.dart'; -import 'package:example/app/modules/home/home_module.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -class HomeWidget extends ModularStatelessWidget { - HomeWidget() { - var c = Modular.get(); - c.addListener(() { - if (c.counter > 10) { - // Modular.to.showDialog( - // child: AlertDialog( - // title: Text('Test'), - // content: Text('Content'), - // ), - // ); - } - }); - } - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("HomeModule"), - actions: [ - FlatButton( - onPressed: () { - Modular.link.pushNamed('/list/${get().counter}'); - }, - child: Text("LIST"), - ) - ], - ), - body: Center( - child: Consumer(builder: (context, value) { - return Text('Counter ${value.counter}'); - }), - ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - onPressed: () { - get().increment(); - //Modular.to.pushNamed('/home'); - }, - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/home/pages/list/list_widget.dart b/flutter_modular/example/lib/app/modules/home/pages/list/list_widget.dart deleted file mode 100644 index 0cd89ca2..00000000 --- a/flutter_modular/example/lib/app/modules/home/pages/list/list_widget.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:example/app/modules/home/home_bloc.dart'; -import 'package:example/app/modules/home/home_module.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -class ListWidget extends ModularStatelessWidget { - final int param; - - ListWidget({Key key, this.param = 1}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("PARAM id = $param"), - ), - body: Center( - child: Text("${Modular.get().counter}"), - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_bloc.dart b/flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_bloc.dart deleted file mode 100644 index 6e7bfd25..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Page1Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_page.dart b/flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_page.dart deleted file mode 100644 index 22a192b3..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/pages/page1/page1_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'page1_bloc.dart'; - -class Page1Page extends StatefulWidget { - final String title; - const Page1Page({Key key, this.title = "Page1"}) : super(key: key); - - @override - _Page1PageState createState() => _Page1PageState(); -} - -class _Page1PageState extends ModularState { - //use 'controller' variable to access controller - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Column( - children: [], - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_bloc.dart b/flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_bloc.dart deleted file mode 100644 index ce35c34c..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Page2Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_page.dart b/flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_page.dart deleted file mode 100644 index 491ee0c5..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/pages/page2/page2_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'page2_bloc.dart'; - -class Page2Page extends StatefulWidget { - final String title; - const Page2Page({Key key, this.title = "Page2"}) : super(key: key); - - @override - _Page2PageState createState() => _Page2PageState(); -} - -class _Page2PageState extends ModularState { - //use 'controller' variable to access controller - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Column( - children: [], - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_bloc.dart b/flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_bloc.dart deleted file mode 100644 index 24344a60..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Page3Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_page.dart b/flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_page.dart deleted file mode 100644 index 034d1495..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/pages/page3/page3_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'page3_bloc.dart'; - -class Page3Page extends StatefulWidget { - final String title; - const Page3Page({Key key, this.title = "Page3"}) : super(key: key); - - @override - _Page3PageState createState() => _Page3PageState(); -} - -class _Page3PageState extends ModularState { - //use 'controller' variable to access controller - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Column( - children: [], - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/shopping/shopping_bloc.dart b/flutter_modular/example/lib/app/modules/shopping/shopping_bloc.dart deleted file mode 100644 index 6eecb0bc..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/shopping_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class ShoppingBloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/shopping/shopping_module.dart b/flutter_modular/example/lib/app/modules/shopping/shopping_module.dart deleted file mode 100644 index e55adcfc..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/shopping_module.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:example/app/modules/shopping/pages/page3/page3_bloc.dart'; -import 'package:example/app/modules/shopping/pages/page2/page2_bloc.dart'; -import 'package:example/app/modules/shopping/pages/page1/page1_bloc.dart'; -import 'package:example/app/modules/shopping/shopping_bloc.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:example/app/modules/shopping/shopping_page.dart'; - -class ShoppingModule extends ChildModule { - @override - List get binds => [ - Bind((i) => Page3Bloc()), - Bind((i) => Page2Bloc()), - Bind((i) => Page1Bloc()), - Bind((i) => ShoppingBloc()), - ]; - - @override - List get routers => [ - ModularRouter('/', child: (_, args) => ShoppingPage()), - ]; - - static Inject get to => Inject.of(); -} diff --git a/flutter_modular/example/lib/app/modules/shopping/shopping_page.dart b/flutter_modular/example/lib/app/modules/shopping/shopping_page.dart deleted file mode 100644 index 73467703..00000000 --- a/flutter_modular/example/lib/app/modules/shopping/shopping_page.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:example/app/modules/shopping/pages/page1/page1_page.dart'; -import 'package:example/app/modules/shopping/pages/page2/page2_page.dart'; -import 'package:example/app/modules/shopping/pages/page3/page3_page.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'shopping_bloc.dart'; - -class ShoppingPage extends StatefulWidget { - final String title; - const ShoppingPage({Key key, this.title = "Shopping"}) : super(key: key); - - @override - _ShoppingPageState createState() => _ShoppingPageState(); -} - -class _ShoppingPageState extends ModularState { - //use 'controller' variable to access controller - - @override - Widget build(BuildContext context) { - return DefaultTabController( - length: 3, - child: Scaffold( - appBar: AppBar( - title: Text(widget.title), - bottom: TabBar(tabs: [ - Tab( - text: "Page1", - ), - Tab( - text: "Page2", - ), - Tab( - text: "Page3", - ) - ]), - ), - body: TabBarView(children: [Page1Page(), Page2Page(), Page3Page()])), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_bloc.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_bloc.dart deleted file mode 100644 index 6e7bfd25..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Page1Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_page.dart deleted file mode 100644 index 50553d59..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page1/page1_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -class Page1Page extends StatefulWidget { - final String title; - const Page1Page({Key key, this.title = "Page1"}) : super(key: key); - - @override - _Page1PageState createState() => _Page1PageState(); -} - -class _Page1PageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: RaisedButton( - child: Text('Go to Page 2'), - onPressed: () { - Navigator.of(context).pushNamed('/page2'); - }), - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_bloc.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_bloc.dart deleted file mode 100644 index ce35c34c..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Page2Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart deleted file mode 100644 index 82d41096..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -class Page2Page extends StatefulWidget { - final String title; - const Page2Page({Key key, this.title = "Page2"}) : super(key: key); - - @override - _Page2PageState createState() => _Page2PageState(); -} - -class _Page2PageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: RaisedButton( - child: Text('Go to Page 3'), - onPressed: () { - Navigator.of(context).pushNamed('/page3'); - }), - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_bloc.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_bloc.dart deleted file mode 100644 index 24344a60..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Page3Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_page.dart deleted file mode 100644 index 823f0243..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page3/page3_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -class Page3Page extends StatefulWidget { - final String title; - const Page3Page({Key key, this.title = "Page3"}) : super(key: key); - - @override - _Page3PageState createState() => _Page3PageState(); -} - -class _Page3PageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: RaisedButton( - child: Text('Go to Page 4'), - onPressed: () { - Navigator.of(context).pushNamed('/page4'); - }), - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_bloc.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_bloc.dart deleted file mode 100644 index c437967f..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Page4Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_page.dart deleted file mode 100644 index ad1ce474..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/pages/page4/page4_page.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -class Page4Page extends StatefulWidget { - final String title; - const Page4Page({Key key, this.title = "Page4"}) : super(key: key); - - @override - _Page4PageState createState() => _Page4PageState(); -} - -class _Page4PageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: RaisedButton( - child: Text('Go to Page 3'), - onPressed: () { - Navigator.of(context).pushNamed('/page3'); - }), - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_bloc.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_bloc.dart deleted file mode 100644 index e2281b45..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Tab1Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_module.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_module.dart deleted file mode 100644 index 5d85f382..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_module.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:example/app/modules/tabs/modules/tab1/pages/page1/page1_page.dart'; -import 'package:example/app/modules/tabs/modules/tab1/pages/page2/page2_bloc.dart'; -import 'package:example/app/modules/tabs/modules/tab1/pages/page1/page1_bloc.dart'; -import 'package:example/app/modules/tabs/modules/tab1/pages/page2/page2_page.dart'; -import 'package:example/app/modules/tabs/modules/tab1/tab1_bloc.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:example/app/modules/tabs/modules/tab1/tab1_page.dart'; - -import 'pages/page3/page3_page.dart'; -import 'pages/page4/page4_page.dart'; - -class Tab1Module extends ChildModule { - @override - List get binds => [ - Bind((i) => Page2Bloc()), - Bind((i) => Page1Bloc()), - Bind((i) => Tab1Bloc()), - ]; - - @override - List get routers => [ - ModularRouter(Modular.initialRoute, child: (_, args) => Tab1Page()), - ModularRouter("/page1", - child: (_, args) => Page1Page(), transition: TransitionType.rotate), - ModularRouter("/page2", - child: (_, args) => Page2Page(), - transition: TransitionType.leftToRight), - ModularRouter( - '/page3', - child: (_, args) => Page3Page(), - transition: TransitionType.custom, - customTransition: CustomTransition( - transitionBuilder: (context, animation, secondaryAnimation, child) { - //Just First Animation - return SlideTransition( - transformHitTests: false, - position: Tween( - begin: const Offset(0.0, 1.0), - end: Offset.zero, - ).chain(CurveTween(curve: Curves.ease)).animate(animation), - child: child); - - // //Using secondaryAnimation - // return SlideTransition( - // transformHitTests: false, - // position: Tween( - // begin: const Offset(0.0, 1.0), - // end: Offset.zero, - // ).chain(CurveTween(curve: Curves.ease)).animate(animation), - // child: SlideTransition( - // transformHitTests: false, - // position: Tween( - // begin: Offset.zero, - // end: const Offset(0.0, -1.0), - // ).chain(CurveTween(curve: Curves.ease)).animate(secondaryAnimation), - // child: child, - // ), - // ); - }, - ), - ), - ModularRouter("/page4", - child: (_, args) => Page4Page(), - transition: TransitionType.rightToLeft), - ]; -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart deleted file mode 100644 index 484c13d2..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab1/tab1_page.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; - -class Tab1Page extends StatefulWidget { - final String title; - const Tab1Page({Key key, this.title = "Tab1"}) : super(key: key); - - @override - _Tab1PageState createState() => _Tab1PageState(); -} - -class _Tab1PageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Center( - child: RaisedButton(onPressed: () { - // Modular.navigator.pushNamed('/page1'); - }), - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_bloc.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_bloc.dart deleted file mode 100644 index 6999f2d6..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_bloc.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; - -class Tab2Bloc extends Disposable { - //dispose will be called automatically by closing its streams - @override - void dispose() {} -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_module.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_module.dart deleted file mode 100644 index 8eac64a9..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_module.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:example/app/modules/tabs/modules/tab2/tab2_bloc.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:example/app/modules/tabs/modules/tab2/tab2_page.dart'; - -class Tab2Module extends ChildModule { - @override - List get binds => [ - Bind((i) => Tab2Bloc()), - ]; - - @override - List get routers => [ - ModularRouter(Modular.initialRoute, child: (_, args) => Tab2Page()), - ]; -} diff --git a/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_page.dart b/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_page.dart deleted file mode 100644 index bc6422b7..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/modules/tab2/tab2_page.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/material.dart'; - -class Tab2Page extends StatefulWidget { - final String title; - const Tab2Page({Key key, this.title = "Tab2"}) : super(key: key); - - @override - _Tab2PageState createState() => _Tab2PageState(); -} - -class _Tab2PageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - ), - body: Column( - children: [], - ), - ); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/tabs_bloc.dart b/flutter_modular/example/lib/app/modules/tabs/tabs_bloc.dart deleted file mode 100644 index ffb83448..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/tabs_bloc.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:rxdart/rxdart.dart'; - -class TabsBloc implements Disposable { - final selectedPage = BehaviorSubject.seeded(0); - TabsBloc(); - - @override - void dispose() { - selectedPage.close(); - } -} diff --git a/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart b/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart deleted file mode 100644 index 203ca7a8..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/tabs_module.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:example/app/modules/tabs/tabs_bloc.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -class TabsModule extends ChildModule { - @override - List get binds => [ - Bind((i) => TabsBloc()), - ]; - - @override - List get routers => [ - // ModularRouter('/', child: (_, args) => TabsPage()), - ]; -} diff --git a/flutter_modular/example/lib/app/modules/tabs/tabs_page.dart b/flutter_modular/example/lib/app/modules/tabs/tabs_page.dart deleted file mode 100644 index e6b4dfb4..00000000 --- a/flutter_modular/example/lib/app/modules/tabs/tabs_page.dart +++ /dev/null @@ -1,60 +0,0 @@ -// import 'package:example/app/modules/tabs/tabs_bloc.dart'; -// import 'package:flutter/material.dart'; -// import 'package:flutter_modular/flutter_modular.dart'; - -// import 'modules/tab1/tab1_module.dart'; -// import 'modules/tab2/tab2_module.dart'; - -// class TabsPage extends StatefulWidget { -// final String title; -// const TabsPage({Key key, this.title = "Tabs"}) : super(key: key); - -// @override -// _TabsPageState createState() => _TabsPageState(); -// } - -// class _TabsPageState extends State { -// var controller = RouterOutletListController(); -// var currentIndex = 0; -// @override -// void initState() { -// controller.listen((value) { -// setState(() { -// currentIndex = value; -// }); -// }); -// super.initState(); -// } - -// @override -// Widget build(BuildContext context) { -// return Scaffold( -// appBar: AppBar( -// title: Text(widget.title), -// actions: [ -// RaisedButton( -// onPressed: () { -// Modular.to.pushNamed('/home'); -// }, -// child: Text('HOME'), -// ) -// ], -// ), -// floatingActionButton: FloatingActionButton( -// child: Icon(Icons.shopping_cart), -// onPressed: () { -// Modular.to.pushNamed("/shopping"); -// }), -// body: RouterOutletList( -// modules: [Tab1Module(), Tab2Module()], controller: controller), -// bottomNavigationBar: BottomNavigationBar( -// currentIndex: currentIndex, -// onTap: controller.changeModule, -// items: [ -// BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), -// BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), -// BottomNavigationBarItem(icon: Icon(Icons.add), title: Text('data')), -// ]), -// ); -// } -// } diff --git a/flutter_modular/example/lib/main.dart b/flutter_modular/example/lib/main.dart deleted file mode 100644 index 3cdf5a15..00000000 --- a/flutter_modular/example/lib/main.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'app/app_module.dart'; - -void main() => runApp(ModularApp(module: AppModule())); diff --git a/flutter_modular/example/lib/main_guardtest.dart b/flutter_modular/example/lib/main_guardtest.dart deleted file mode 100644 index fe39d88a..00000000 --- a/flutter_modular/example/lib/main_guardtest.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -void main() => runApp(ModularApp(module: AppModule())); - -class AppModule extends MainModule { - @override - List get binds => []; - - @override - Widget get bootstrap => MyApp(); - - @override - List get routers => [ - ModularRouter('/', module: HomeModule()), - ModularRouter('/profile', - module: ProfileModule(), guards: [AuthGuard()]), - ]; -} - -class HomeModule extends ChildModule { - @override - List get binds => []; - - @override - List get routers => [ - ModularRouter('/', child: (_, __) => MyHomePage()), - ]; -} - -class ProfileModule extends ChildModule { - @override - List get binds => []; - - @override - List get routers => [ - ModularRouter('/', child: (_, __) => ProfilePage()), - ]; -} - -class AuthGuard extends RouteGuard { - @override - bool canActivate(String url) { - return false; - } - - @override - List get executors => [AuthExecutor()]; -} - -class AuthExecutor extends GuardExecutor { - @override - onGuarded(String path, {bool isActive}) { - print(isActive); - } -} - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - // navigatorKey: Modular.navigatorKey, - initialRoute: '/', - // onGenerateRoute: Modular.generateRoute, - ); - } -} - -class MyHomePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("Home"), - ), - body: Center( - child: Icon(Icons.home, size: 64), - ), - floatingActionButton: FloatingActionButton.extended( - onPressed: () { - Modular.to.pushNamed('/profile'); - }, - label: Text("Entrar"), - ), - ); - } -} - -class ProfilePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("Logged In!"), - ), - body: Center(child: Icon(Icons.verified_user, size: 64)), - ); - } -} diff --git a/flutter_modular/example/macos/.gitignore b/flutter_modular/example/macos/.gitignore deleted file mode 100644 index d2fd3772..00000000 --- a/flutter_modular/example/macos/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/xcuserdata/ diff --git a/flutter_modular/example/macos/Flutter/Flutter-Debug.xcconfig b/flutter_modular/example/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index c2efd0b6..00000000 --- a/flutter_modular/example/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_modular/example/macos/Flutter/Flutter-Release.xcconfig b/flutter_modular/example/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index c2efd0b6..00000000 --- a/flutter_modular/example/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_modular/example/macos/Flutter/GeneratedPluginRegistrant.swift b/flutter_modular/example/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index cccf817a..00000000 --- a/flutter_modular/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,10 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { -} diff --git a/flutter_modular/example/macos/Runner.xcodeproj/project.pbxproj b/flutter_modular/example/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 331479d3..00000000 --- a/flutter_modular/example/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,596 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 51; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; }; - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; }; - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */, - 33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */, - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D73912F022F37F9E000D13A0 /* App.framework in Frameworks */, - 33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* example.app */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - D73912EF22F37F9E000D13A0 /* App.framework */, - 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* example.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0930; - ORGANIZATIONNAME = "The Flutter Authors"; - TargetAttributes = { - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh\ntouch Flutter/ephemeral/tripwire\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter/ephemeral", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter/ephemeral", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter/ephemeral", - ); - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/flutter_modular/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_modular/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/flutter_modular/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_modular/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_modular/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index df12c333..00000000 --- a/flutter_modular/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_modular/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/flutter_modular/example/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/flutter_modular/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/flutter_modular/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_modular/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/flutter_modular/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/flutter_modular/example/macos/Runner/AppDelegate.swift b/flutter_modular/example/macos/Runner/AppDelegate.swift deleted file mode 100644 index d53ef643..00000000 --- a/flutter_modular/example/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Cocoa -import FlutterMacOS - -@NSApplicationMain -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } -} diff --git a/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f1..00000000 --- a/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 3c4935a7ca84f0976aca34b7f2895d65fb94d1ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46993 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 diff --git a/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index ed4cc16421680a50164ba74381b4b35ceaa0ccfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3276 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 N;OXk;vd$@?2>?>Ex^Vyi diff --git a/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bcbf36df2f2aaaa0a63c7dabc94e600184229d0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5933 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 f$KZHO*s&vt|9^w-6P?|#0pRK8NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!ItFh?!xdN1Q+aGJ{c&& zS>O>_%)r1c48n{Iv*t(u1=&kHeO=ifbFy+6aSK)V_AxLppYn8Z42d|rc6w}vOsL55 z`t&mC&y2@JTEyg!eDiFX^k#CC!jq%>erB=yHqUP0XcDOTw6ko}L zX;EmMrq(fKk*eygEuA616;0)>@A{TK|55PV@70 z$OfzS*(VJxQev3J?yY?O=ul(v`fp}?u9z`JK3ugibK>)DyCwImZOF4d{xK%%Ks1*} zv$oa)9anR%lXIBUqYnhLmT>VOzHfNP?ZwJNZ!5$s9M08RynIvaXw>@G^T9@r9^KH1 zVy??F&uuk)bH9Y4pQY!hP58i_H6 znl-NcuCpLV6ZWU;4C zu@9exF&OZi`Bovq_m%T+WhU2kvkz@^_LpycBvqm3bMpLw8X-Or5sL>0AKE1$(k_L=_Zc=CUq#=x1-QZf)G7nHu@fmsQ1eN_N3+nTEz`4HI4Z6uVlE zJH+X&det8JU?tO?upcM4Z=cV!JV;yF>FfL5Q$M|W_2Z!P`S=}Wzp|_1^#d%e?_H`> zV@%vA$+bFVqhw9`U;TfP|5|PD{||OiYdor8P*i??|NJcb%kzT_73*7WE?Ua5hAnR2 z=7WE=PhTlJ#ZeRznjTUb;`E(wkMZrj4e|Hilz-mK>9cZHQY**5TUPw~u}k;u73KI}xAx!0m-)GVia|x^d3p~s_9gh83jA&Ra<8rM%`>U3x69t&NzbwWY}7Ar?)FK#IZ0z|d0H0EkRO w3{9;}4Xg|ebq&m|3=9_N6z8I7$jwj5OsmAL;bP(Gi$Dzwp00i_>zopr02+f8CIA2c diff --git a/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/flutter_modular/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index e71a726136a47ed24125c7efc79d68a4a01961b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14800 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/flutter_modular/example/macos/Runner/Configs/AppInfo.xcconfig b/flutter_modular/example/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 1c34a704..00000000 --- a/flutter_modular/example/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = example - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.example - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2020 com.example. All rights reserved. diff --git a/flutter_modular/example/macos/Runner/Configs/Debug.xcconfig b/flutter_modular/example/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd94..00000000 --- a/flutter_modular/example/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/flutter_modular/example/macos/Runner/Configs/Release.xcconfig b/flutter_modular/example/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f495..00000000 --- a/flutter_modular/example/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/flutter_modular/example/macos/Runner/Configs/Warnings.xcconfig b/flutter_modular/example/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf47..00000000 --- a/flutter_modular/example/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/flutter_modular/example/macos/Runner/DebugProfile.entitlements b/flutter_modular/example/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a30..00000000 --- a/flutter_modular/example/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/flutter_modular/example/macos/Runner/Info.plist b/flutter_modular/example/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6..00000000 --- a/flutter_modular/example/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/flutter_modular/example/macos/Runner/MainFlutterWindow.swift b/flutter_modular/example/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 2722837e..00000000 --- a/flutter_modular/example/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/flutter_modular/example/macos/Runner/Release.entitlements b/flutter_modular/example/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a4..00000000 --- a/flutter_modular/example/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/flutter_modular/example/pubspec.yaml b/flutter_modular/example/pubspec.yaml deleted file mode 100644 index af11de92..00000000 --- a/flutter_modular/example/pubspec.yaml +++ /dev/null @@ -1,85 +0,0 @@ -name: example -description: A new Flutter project. - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.1.0 <3.0.0" - -dependencies: - - mobx: ^1.2.1+1 - rxdart: ^0.23.1 - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 - flutter_modular: 2.0.0 - -dev_dependencies: - mobx_codegen: - build_runner: ^1.10.1 - modular_codegen: 2.0.0 - flutter_test: - sdk: flutter - -dependency_overrides: - flutter_modular: - path: ../../flutter_modular - modular_codegen: - path: ../../modular_codegen - - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_modular/example/web/favicon.png b/flutter_modular/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/flutter_modular/example/web/icons/Icon-192.png b/flutter_modular/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/flutter_modular/example/web/icons/Icon-512.png b/flutter_modular/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/flutter_modular/example/web/index.html b/flutter_modular/example/web/index.html deleted file mode 100644 index 6eff9a74..00000000 --- a/flutter_modular/example/web/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - example - - - - - diff --git a/flutter_modular/example/web/manifest.json b/flutter_modular/example/web/manifest.json deleted file mode 100644 index c6380010..00000000 --- a/flutter_modular/example/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "minimal-ui", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index fb7ba6c5..f4ad4160 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -15,7 +15,5 @@ export 'src/routers/route_link.dart'; export 'src/utils/modular_arguments.dart'; export 'src/widgets/consumer_widget.dart'; export 'src/widgets/modular_app.dart'; -export 'src/widgets/modular_stateful_widget_state.dart'; -export 'src/widgets/modular_stateless_widget.dart'; export 'src/widgets/router_outlet.dart'; export 'src/widgets/widget_module.dart'; diff --git a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart b/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart deleted file mode 100644 index 957d75cb..00000000 --- a/flutter_modular/lib/src/navigator/modular_navigator_outlet.dart +++ /dev/null @@ -1,18 +0,0 @@ -// import 'package:flutter/widgets.dart'; - -// import '../routers/modular_navigator.dart'; - -// class ModularNavigatorOutlet extends ModularNavigator { -// final NavigatorState global; -// final NavigatorState module; -// ModularNavigatorOutlet({this.module, this.global}) : super(module); - -// @override -// void pop([T result]) { -// if (module.canPop()) { -// module.pop(); -// } else { -// global.pop(); -// } -// } -// } diff --git a/flutter_modular/lib/src/widgets/modular_stateful_widget_state.dart b/flutter_modular/lib/src/widgets/modular_stateful_widget_state.dart deleted file mode 100644 index 5764113a..00000000 --- a/flutter_modular/lib/src/widgets/modular_stateful_widget_state.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../../flutter_modular.dart'; - -abstract class ModularState - extends State { - final TBind controller = Modular.get(); - - @override - void dispose() { - super.dispose(); - Modular.dispose(); - } -} - -mixin ModularStateMixin on State { - final TBind controller = Modular.get(); - - @override - void dispose() { - super.dispose(); - Modular.dispose(); - } -} diff --git a/flutter_modular/lib/src/widgets/modular_stateless_widget.dart b/flutter_modular/lib/src/widgets/modular_stateless_widget.dart deleted file mode 100644 index 0b3dc6ea..00000000 --- a/flutter_modular/lib/src/widgets/modular_stateless_widget.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../../flutter_modular.dart'; - -abstract class ModularStatelessWidget - extends StatelessWidget with InjectWidgetMixin { - ModularStatelessWidget({Key key}) : super(key: key); -} From a533847a3c8eb0924ee0d0a851e45114f70563de Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 25 Oct 2020 23:10:49 -0300 Subject: [PATCH 10/71] Delete not used files --- flutter_modular/lib/flutter_modular.dart | 2 - flutter_modular/lib/src/inject/inject.dart | 25 ------- .../lib/src/routers/route_link.dart | 71 ------------------- .../lib/src/widgets/consumer_widget.dart | 45 ------------ .../test/routers/route_link_test.dart | 25 ------- 5 files changed, 168 deletions(-) delete mode 100644 flutter_modular/lib/src/routers/route_link.dart delete mode 100644 flutter_modular/lib/src/widgets/consumer_widget.dart delete mode 100644 flutter_modular/test/routers/route_link_test.dart diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index f4ad4160..7cad1e80 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -11,9 +11,7 @@ export 'src/interfaces/modular_navigator_interface.dart'; export 'src/interfaces/route_guard.dart'; export 'src/modular_base.dart'; export 'src/routers/modular_router.dart'; -export 'src/routers/route_link.dart'; export 'src/utils/modular_arguments.dart'; -export 'src/widgets/consumer_widget.dart'; export 'src/widgets/modular_app.dart'; export 'src/widgets/router_outlet.dart'; export 'src/widgets/widget_module.dart'; diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/lib/src/inject/inject.dart index cd877c06..83491eab 100644 --- a/flutter_modular/lib/src/inject/inject.dart +++ b/flutter_modular/lib/src/inject/inject.dart @@ -38,11 +38,6 @@ class Inject { } } - // ModularArguments get args => Modular.args; - - /// get current module link - RouteLink get link => Modular.link; - void dispose() { if (T.runtimeType.toString() == 'dynamic') { Modular.dispose(); @@ -57,23 +52,3 @@ mixin InjectMixinBase { S get() => _inject.get(); } - -/// A mixin that must be used only with classes that extends a [Widget] -/// [T] the module to be injected on the widget. -mixin InjectWidgetMixin on Widget - implements InjectMixinBase { - final Inject _inject = Inject.of(); - - S get({Map params}) => - Modular.get(module: T.toString(), params: params); - - Widget consumer({ - Widget Function(BuildContext context, S value) builder, - bool Function(S oldValue, S newValue) distinct, - }) { - return Consumer( - builder: builder, - distinct: distinct, - ); - } -} diff --git a/flutter_modular/lib/src/routers/route_link.dart b/flutter_modular/lib/src/routers/route_link.dart deleted file mode 100644 index b6e7c839..00000000 --- a/flutter_modular/lib/src/routers/route_link.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../flutter_modular.dart'; - -class RouteLink extends IModularNavigator { - final String path; - final String modulePath; - final NavigatorState navigator; - - RouteLink(this.navigator, {this.path, this.modulePath = "/"}); - - RouteLink copy() { - return RouteLink(navigator, path: path, modulePath: modulePath); - } - - @override - bool canPop() => navigator.canPop(); - - @override - Future maybePop([T result]) { - return navigator.maybePop(result); - } - - @override - void pop([T result]) => navigator.pop(result); - - @override - Future popAndPushNamed( - String routeName, - {TO result, - Object arguments}) => - navigator.popAndPushNamed(_checkpath(routeName), - result: result, arguments: arguments); - - @override - void popUntil(bool Function(Route) predicate) => - navigator.popUntil(predicate); - - @override - Future push(Route route) => navigator.push(route); - - @override - Future pushNamed(String routeName, {Object arguments}) => - navigator.pushNamed(_checkpath(routeName), arguments: arguments); - - @override - Future pushNamedAndRemoveUntil( - String newRouteName, bool Function(Route) predicate, - {Object arguments}) => - navigator.pushNamedAndRemoveUntil(_checkpath(newRouteName), predicate, - arguments: arguments); - @override - Future pushReplacementNamed( - String routeName, - {TO result, - Object arguments}) => - navigator.pushReplacementNamed(_checkpath(routeName), - result: result, arguments: arguments); - - @override - Future pushReplacement( - Route newRoute, - {TO result}) => - navigator.pushReplacement(newRoute, result: result); - - String _checkpath(String routeName) { - routeName = routeName[0] == '/' ? routeName : '/$routeName'; - var newPath = "$modulePath$routeName".replaceAll('//', '/'); - return newPath; - } -} diff --git a/flutter_modular/lib/src/widgets/consumer_widget.dart b/flutter_modular/lib/src/widgets/consumer_widget.dart deleted file mode 100644 index aa402103..00000000 --- a/flutter_modular/lib/src/widgets/consumer_widget.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../../flutter_modular.dart'; - -class Consumer extends StatefulWidget { - final Widget Function(BuildContext context, T value) builder; - final bool Function(T oldValue, T newValue) distinct; - - Consumer({ - Key key, - @required this.builder, - this.distinct, - }) : super(key: key); - - @override - _ConsumerState createState() => _ConsumerState(); -} - -class _ConsumerState extends State> { - T value; - - void listener() { - final newValue = Modular.get(); - if (widget.distinct == null || widget.distinct(value, newValue)) { - setState(() => value = newValue); - } - } - - @override - void initState() { - super.initState(); - value = Modular.get(); - value.addListener(listener); - } - - @override - void dispose() { - value.removeListener(listener); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return widget.builder(context, value); - } -} diff --git a/flutter_modular/test/routers/route_link_test.dart b/flutter_modular/test/routers/route_link_test.dart deleted file mode 100644 index f9734ccb..00000000 --- a/flutter_modular/test/routers/route_link_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -class NavigatorMock extends Mock implements RouteLink {} - -void main() { - RouteLink link; - - setUpAll(() { - link = NavigatorMock(); - }); - - group('Navigation', () { - test('canPop', () { - when(link.canPop()).thenReturn(true); - expect(link.canPop(), true); - }); - - test('maybePop', () { - when(link.maybePop()).thenAnswer((_) => Future.value(true)); - expect(link.maybePop(), completion(true)); - }); - }); -} From da1c91a4d45820991024f3585944f2bff299806f Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 25 Oct 2020 23:17:31 -0300 Subject: [PATCH 11/71] remove comments --- flutter_modular/lib/src/modular_base.dart | 273 ---------------------- 1 file changed, 273 deletions(-) diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index 049996a7..56b0d2e2 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -61,276 +61,3 @@ extension ModularExtension on MaterialApp { return app; } } - -// class _Modular { -// static ChildModule _initialModule; -// static ModularArguments _args; -// static ModularArguments get args => _args?.copy(); -// static List currentModule = []; -// static final Map> _navigators = -// >{}; - -// static void init(ChildModule module) { -// _initialModule = module; -// bindModule(module, "global=="); -// } - -// @visibleForTesting -// static void bindModule(ChildModule module, [String path]) { -// assert(module != null); -// final name = module.runtimeType.toString(); -// if (!_injectMap.containsKey(name)) { -// module.paths.add(path); -// _injectMap[name] = module; -// module.instance(); -// _debugPrintModular("-- ${module.runtimeType.toString()} INITIALIZED"); -// } else { -// _injectMap[name].paths.add(path); -// } -// } - -// static void removeModule(ChildModule module, [String name]) { -// name ??= module.runtimeType.toString(); -// if (_injectMap.containsKey(name)) { -// _injectMap[name].cleanInjects(); -// _injectMap.remove(name); -// if (_navigators.containsKey(name)) { -// _navigators.remove(name); -// currentModule.remove(name); -// } -// } -// } - -// @visibleForTesting -// static String prepareToRegex(String url) { -// final newUrl = []; -// for (var part in url.split('/')) { -// var url = part.contains(":") ? "(.*?)" : part; -// newUrl.add(url); -// } - -// return newUrl.join("/"); -// } - -// @visibleForTesting -// static dynamic convertType(String value) { -// if (int.tryParse(value) != null) { -// return int.parse(value); -// } else if (double.tryParse(value) != null) { -// return double.parse(value); -// } else if (value.toLowerCase() == 'true') { -// return true; -// } else if (value.toLowerCase() == 'false') { -// return false; -// } - -// return value; -// } - -// @visibleForTesting -// static bool searchRoute( -// ModularRouter router, String routeNamed, String path) { -// if (routeNamed.split('/').length != path.split('/').length) { -// return false; -// } - -// if (routeNamed.contains('/:')) { -// final regExp = RegExp( -// "^${prepareToRegex(routeNamed)}\$", -// caseSensitive: true, -// ); -// var r = regExp.firstMatch(path); -// if (r != null) { -// final params = {}; -// var paramPos = 0; -// final routeParts = routeNamed.split('/'); -// final pathParts = path.split('/'); - -// // print('Match! Processing $path as $routeNamed'); - -// for (var routePart in routeParts) { -// if (routePart.contains(":")) { -// var paramName = routePart.replaceFirst(':', ''); -// if (pathParts[paramPos].isNotEmpty) { -// params[paramName] = pathParts[paramPos]; -// routeNamed = -// routeNamed.replaceFirst(routePart, params[paramName]); -// } -// } -// paramPos++; -// } - -// // print('Result processed $path as $routeNamed'); - -// if (routeNamed != path) { -// router.params = null; -// return false; -// } - -// router.params = params; -// return true; -// } - -// router.params = null; -// return false; -// } - -// return routeNamed == path; -// } - -// static RouteGuard _verifyGuard(List guards, String path) { -// RouteGuard guard; -// var realGuards = guards ?? []; -// guard = realGuards.length == 0 -// ? null -// : guards.firstWhere((guard) => !guard.canActivate(path), -// orElse: () => null); - -// realGuards -// .expand((c) => c.executors) -// .forEach((c) => c.onGuarded(path, isActive: guard == null)); - -// if (guard != null) { -// throw ModularError("Path guarded : $path"); -// } -// return guard; -// } - -// static List _masterRouteGuards; - -// static ModularRouter _searchInModule( -// ChildModule module, String routerName, String path) { -// path = "/$path".replaceAll('//', '/'); -// final routers = module.routers; -// routers.sort((preview, actual) { -// return preview.routerName.contains('/:') ? 1 : 0; -// }); -// for (var route in routers) { -// final tempRouteName = -// (routerName + route.routerName).replaceFirst('//', '/'); -// if (route.child == null) { -// _masterRouteGuards = route.guards; -// var _routerName = -// ('$routerName${route.routerName}/').replaceFirst('//', '/'); -// ModularRouter router; -// if (_routerName == path || _routerName == "$path/") { -// final guard = _verifyGuard(route.guards, path); -// if (guard != null) { -// return null; -// } -// router = route.module.routers[0]; -// if (router.module != null) { -// var _routerName = -// (routerName + route.routerName).replaceFirst('//', '/'); -// router = _searchInModule(route.module, _routerName, path); -// } -// } else { -// router = _searchInModule(route.module, _routerName, path); -// } - -// if (router != null) { -// router = router.modulePath == null -// ? router.copyWith(modulePath: tempRouteName) -// : router; -// if (_routerName == path || _routerName == "$path/") { -// final guard = _verifyGuard(router.guards, path); -// if (guard != null) { -// return null; -// } -// } - -// if (router.transition == TransitionType.defaultTransition) { -// router = router.copyWith( -// transition: route.transition, -// customTransition: route.customTransition, -// ); -// } -// bindModule(route.module, path); -// return router; -// } -// } else { -// if (searchRoute(route, tempRouteName, path)) { -// var guards = _prepareGuardList(_masterRouteGuards, route.guards); -// _masterRouteGuards = null; -// var guard = _verifyGuard(guards, path); -// if ((tempRouteName == path || tempRouteName == "$path/") && -// path != '/') { -// guard = _verifyGuard(guards, path); -// } -// return guard == null ? route : null; -// } -// } -// } -// return null; -// } - -// static List _prepareGuardList( -// List moduleGuard, List routeGuard) { -// if (moduleGuard == null) { -// moduleGuard = []; -// } -// if (routeGuard == null) { -// routeGuard = []; -// } - -// return List.from([...moduleGuard, ...routeGuard]); -// } - -// @visibleForTesting -// static ModularRouter selectRoute(String path, [ChildModule module]) { -// if (path.isEmpty) { -// throw Exception("Router can not be empty"); -// } -// final route = _searchInModule(module ?? _initialModule, "", path); -// return route; -// } - -// static void oldProccess(Old $old) { -// if ($old?.args != null) _args = $old?.args?.copy(); -// if ($old?.link != null) _routeLink = $old?.link?.copy(); -// } - -// static Route generateRoute(RouteSettings settings, -// [ChildModule module, void Function(String) onChangeRoute]) { -// final isRouterOutlet = module != null; -// final path = settings.name; -// var router = selectRoute(path, module); -// if (router == null) { -// return null; -// } -// if (!isRouterOutlet) { -// _old = Old( -// args: args, -// link: link, -// ); -// //updateCurrentModule("app"); -// } - -// _args = ModularArguments(router.params, settings.arguments); - -// _routeLink = RouteLink(path: path, modulePath: router.modulePath); - -// if (settings.name == Modular.initialRoute) { -// router = router.copyWith(transition: TransitionType.noTransition); -// } - -// if (onChangeRoute != null) { -// onChangeRoute(path); -// } - -// return router.getPageRoute( -// settings: settings, -// injectMap: _injectMap, -// isRouterOutlet: isRouterOutlet); -// } - -// static void addCoreInit(ChildModule module) { -// var tagText = module.runtimeType.toString(); -// addCoreInitFromTag(module, tagText); -// } - -// static void addCoreInitFromTag(ChildModule module, String tagText) { -// module.instance(); -// _injectMap[tagText] = module; -// } -// } From b3264578320eccf77d89cd96c2315007d737503d Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Mon, 26 Oct 2020 00:03:17 -0300 Subject: [PATCH 12/71] refact --- flutter_modular/CHANGELOG.md | 6 ++++++ flutter_modular/lib/flutter_modular.dart | 1 + .../src/delegates/modular_router_delegate.dart | 18 ++++++------------ flutter_modular/lib/src/inject/inject.dart | 1 - .../lib/src/routers/modular_page.dart | 3 ++- .../lib/src/widgets/modular_state.dart | 14 ++++++++++++++ 6 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 flutter_modular/lib/src/widgets/modular_state.dart diff --git a/flutter_modular/CHANGELOG.md b/flutter_modular/CHANGELOG.md index cfb64e8c..c8d876b1 100644 --- a/flutter_modular/CHANGELOG.md +++ b/flutter_modular/CHANGELOG.md @@ -1,3 +1,9 @@ +## [3.0.0] - +* Navigator 2.0 +* Removed Modular.link +* Refactor RouteGuard +* Added Modular.to.navigate and Modular.to.navigateByUrl + ## [2.0.1] - 21 Sep 2020 * added onChangeRoute propety in RouterOutlet diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 7cad1e80..5fd225b1 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -13,5 +13,6 @@ export 'src/modular_base.dart'; export 'src/routers/modular_router.dart'; export 'src/utils/modular_arguments.dart'; export 'src/widgets/modular_app.dart'; +export 'src/widgets/modular_state.dart'; export 'src/widgets/router_outlet.dart'; export 'src/widgets/widget_module.dart'; diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index 8b2197d9..b286de78 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -15,10 +15,12 @@ class ModularRouterDelegate extends RouterDelegate ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); + ModularRouter _router; + List _pages = []; @override - ModularRouter get currentConfiguration => _pages.last.router; + ModularRouter get currentConfiguration => _router; @override Widget build(BuildContext context) { @@ -33,16 +35,12 @@ class ModularRouterDelegate extends RouterDelegate @override Future setNewRoutePath(ModularRouter router) async { - final index = _pages.indexWhere((element) => element.router == router); final page = ModularPage( key: ValueKey('url:${router.path}'), router: router, ); - if (index == -1) { - _pages.add(page); - } else { - _pages[index] = page; - } + _pages.last = page; + _router = router; rebuildPages(); } @@ -59,11 +57,7 @@ class ModularRouterDelegate extends RouterDelegate } bool _onPopPage(Route route, dynamic result) { - if (!route.didPop(result)) { - return false; - } - - if (route.isFirst) { + if (!route.didPop(result) || route.isFirst) { return false; } diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/lib/src/inject/inject.dart index 83491eab..e54b446b 100644 --- a/flutter_modular/lib/src/inject/inject.dart +++ b/flutter_modular/lib/src/inject/inject.dart @@ -1,4 +1,3 @@ -import 'package:flutter/widgets.dart'; import '../../flutter_modular.dart'; import '../modular_base.dart'; diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/lib/src/routers/modular_page.dart index 34dfc0d8..afde874c 100644 --- a/flutter_modular/lib/src/routers/modular_page.dart +++ b/flutter_modular/lib/src/routers/modular_page.dart @@ -4,7 +4,8 @@ import '../../flutter_modular.dart'; class ModularPage extends Page { final ModularRouter router; - const ModularPage({Key key, this.router}) : super(key: key); + ModularPage({Key key, this.router}) + : super(key: key, name: router.path, arguments: router.args.data); @override Route createRoute(BuildContext context) { diff --git a/flutter_modular/lib/src/widgets/modular_state.dart b/flutter_modular/lib/src/widgets/modular_state.dart new file mode 100644 index 00000000..064a5009 --- /dev/null +++ b/flutter_modular/lib/src/widgets/modular_state.dart @@ -0,0 +1,14 @@ +import 'package:flutter/widgets.dart'; + +import '../../flutter_modular.dart'; + +abstract class ModularState + extends State { + final TBind controller = Modular.get(); + + @override + void dispose() { + super.dispose(); + Modular.dispose(); + } +} From 3ac9137e2d7f7125a490d34566a8473d7302b14d Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 27 Oct 2020 23:54:55 -0300 Subject: [PATCH 13/71] added modular route class --- flutter_modular/lib/src/routers/modular_page.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/lib/src/routers/modular_page.dart index afde874c..481d87ab 100644 --- a/flutter_modular/lib/src/routers/modular_page.dart +++ b/flutter_modular/lib/src/routers/modular_page.dart @@ -1,14 +1,23 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import '../../flutter_modular.dart'; -class ModularPage extends Page { +class ModularPage extends Page { final ModularRouter router; + final popRoute = Completer(); ModularPage({Key key, this.router}) : super(key: key, name: router.path, arguments: router.args.data); @override - Route createRoute(BuildContext context) { + Route createRoute(BuildContext context) { return router.getPageRoute(this); } } + +class ModularRoute extends Route { + final ModularPage page; + + ModularRoute(this.page) : super(settings: page); +} From 8277d4b57687a46039460cb7965e2cd5d5c1d1e6 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 27 Oct 2020 23:55:30 -0300 Subject: [PATCH 14/71] delegate implements IModularNavigator --- .../delegates/modular_router_delegate.dart | 98 ++++++++++++++++--- flutter_modular/lib/src/modular_impl.dart | 10 +- 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index b286de78..d78b88ef 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -8,13 +8,17 @@ class ModularRouterDelegate extends RouterDelegate with // ignore: prefer_mixin ChangeNotifier, - PopNavigatorRouterDelegateMixin { + PopNavigatorRouterDelegateMixin + implements + IModularNavigator { final GlobalKey navigatorKey; final ModularRouteInformationParser parser; final Map injectMap; ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); + NavigatorState get navigator => navigatorKey.currentState; + ModularRouter _router; List _pages = []; @@ -39,23 +43,16 @@ class ModularRouterDelegate extends RouterDelegate key: ValueKey('url:${router.path}'), router: router, ); - _pages.last = page; + if (_pages.isEmpty) { + _pages.add(page); + } else { + _pages.last = page; + } _router = router; rebuildPages(); } - Future pushNamed(String path, {Object arguments}) async { - var router = parser.selectRoute(path); - router = router.copyWith(args: router?.args?.copyWith(data: arguments)); - final page = ModularPage( - router: router, - ); - _pages.add(page); - rebuildPages(); - return router.popRoute.future; - } - bool _onPopPage(Route route, dynamic result) { if (!route.didPop(result) || route.isFirst) { return false; @@ -63,7 +60,7 @@ class ModularRouterDelegate extends RouterDelegate final page = route.settings as ModularPage; final path = page.router.path; - page.router.popRoute.complete(result); + page.popRoute.complete(result); _pages.removeLast(); rebuildPages(); @@ -90,4 +87,77 @@ class ModularRouterDelegate extends RouterDelegate _pages = List.from(_pages); notifyListeners(); } + + @override + Future pushNamed(String routeName, + {Object arguments}) async { + var router = parser.selectRoute(path); + router = router.copyWith(args: router?.args?.copyWith(data: arguments)); + final page = ModularPage( + router: router, + ); + _pages.add(page); + rebuildPages(); + return page.popRoute.future; + } + + @override + Future pushReplacementNamed( + String routeName, + {TO result, + Object arguments}) { + var router = parser.selectRoute(path); + router = router.copyWith(args: router?.args?.copyWith(data: arguments)); + final page = ModularPage( + router: router, + ); + + _onPopPage(ModularRoute(_pages.last), result); + _pages.add(page); + rebuildPages(); + return page.popRoute.future; + } + + @override + bool canPop() => navigator.canPop(); + + @override + Future maybePop([T result]) => + navigator.maybePop(result); + + @override + void pop([T result]) => navigator.pop(result); + + @override + Future push(Route route) { + return navigator.push(route); + } + + @override + Future popAndPushNamed( + String routeName, + {TO result, + Object arguments}) => + navigator.popAndPushNamed( + routeName, + result: result, + arguments: arguments, + ); + + @override + void popUntil(bool Function(Route) predicate) => + navigator.popUntil(predicate); + + @override + Future pushNamedAndRemoveUntil( + String newRouteName, bool Function(Route) predicate, + {Object arguments}) => + navigator.pushNamedAndRemoveUntil(newRouteName, predicate, + arguments: arguments); + + @override + String get modulePath => _router.modulePath; + + @override + String get path => _router.path; } diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index 2785a821..e734eb06 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -10,15 +10,13 @@ ChildModule _initialModule; class ModularImpl implements ModularInterface { final ModularRouterDelegate routerDelegate; final Map injectMap; - IModularNavigator toNavigator; + IModularNavigator navigatorDelegate; ModularImpl({ this.routerDelegate, this.injectMap, - IModularNavigator navigatorDelegate, - }) { - toNavigator = navigatorDelegate ?? ModularNavigator(routerDelegate); - } + this.navigatorDelegate, + }); @override ChildModule get initialModule => _initialModule; @@ -51,7 +49,7 @@ class ModularImpl implements ModularInterface { } @override - IModularNavigator get to => toNavigator; + IModularNavigator get to => navigatorDelegate ?? routerDelegate; @override IModularNavigator get link => throw UnimplementedError(); From e6bb86c72e418f30ecfc4a3a72d0a13b676a9170 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 28 Oct 2020 01:12:20 -0300 Subject: [PATCH 15/71] constants values ModularRouter --- .../modular_route_information_parser.dart | 25 +++--- .../delegates/modular_router_delegate.dart | 26 +++--- .../modular_navigator_interface.dart | 20 ----- .../lib/src/routers/modular_navigator.dart | 14 ++-- .../lib/src/routers/modular_page.dart | 24 +++++- .../lib/src/routers/modular_router.dart | 83 ++++++++----------- 6 files changed, 86 insertions(+), 106 deletions(-) diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart index 65dce9da..c98c3df7 100644 --- a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart @@ -75,7 +75,8 @@ class ModularRouteInformationParser return router; } } else { - if (_parseUrlParams(route, tempRouteName, path)) { + route = _parseUrlParams(route, tempRouteName, path); + if (route != null) { Modular.bindModule(route.currentModule, path); return route.copyWith(path: path); } @@ -94,9 +95,10 @@ class ModularRouteInformationParser return newUrl.join("/"); } - bool _parseUrlParams(ModularRouter router, String routeNamed, String path) { + ModularRouter _parseUrlParams( + ModularRouter router, String routeNamed, String path) { if (routeNamed.split('/').length != path.split('/').length) { - return false; + return null; } if (routeNamed.contains('/:')) { @@ -106,7 +108,7 @@ class ModularRouteInformationParser ); var r = regExp.firstMatch(path); if (r != null) { - final params = {}; + var params = {}; var paramPos = 0; final routeParts = routeNamed.split('/'); final pathParts = path.split('/'); @@ -125,21 +127,14 @@ class ModularRouteInformationParser paramPos++; } - // print('Result processed $path as $routeNamed'); - - if (routeNamed != path) { - router.args = router.args.copyWith(params: null); - return false; - } - router.args = router.args.copyWith(params: params); - return true; + params = routeNamed != path ? null : params; + return router.copyWith(args: router.args.copyWith(params: params)); } - router.args = router.args.copyWith(params: null); - return false; + return router.copyWith(args: router.args.copyWith(params: null)); } - return routeNamed == path; + return router; } ModularRouter selectRoute(String path, [ChildModule module]) { diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index d78b88ef..ad45f8f7 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -60,7 +60,7 @@ class ModularRouterDelegate extends RouterDelegate final page = route.settings as ModularPage; final path = page.router.path; - page.popRoute.complete(result); + page.completePop(result); _pages.removeLast(); rebuildPages(); @@ -91,14 +91,14 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamed(String routeName, {Object arguments}) async { - var router = parser.selectRoute(path); + var router = parser.selectRoute(routeName); router = router.copyWith(args: router?.args?.copyWith(data: arguments)); final page = ModularPage( router: router, ); _pages.add(page); rebuildPages(); - return page.popRoute.future; + return page.waitPop(); } @override @@ -106,20 +106,23 @@ class ModularRouterDelegate extends RouterDelegate String routeName, {TO result, Object arguments}) { - var router = parser.selectRoute(path); + var router = parser.selectRoute(routeName); router = router.copyWith(args: router?.args?.copyWith(data: arguments)); - final page = ModularPage( + final page = ModularPage( router: router, ); - _onPopPage(ModularRoute(_pages.last), result); - _pages.add(page); + _pages.last.completePop(result); + + _pages.last = page; rebuildPages(); - return page.popRoute.future; + return page.waitPop(); } @override - bool canPop() => navigator.canPop(); + bool canPop() { + return navigator.canPop(); + } @override Future maybePop([T result]) => @@ -128,11 +131,6 @@ class ModularRouterDelegate extends RouterDelegate @override void pop([T result]) => navigator.pop(result); - @override - Future push(Route route) { - return navigator.push(route); - } - @override Future popAndPushNamed( String routeName, diff --git a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart index 1de9aa3e..de03c40d 100644 --- a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart @@ -4,13 +4,6 @@ abstract class IModularNavigator { String get path; String get modulePath; - /// Navigate to a new screen. - /// - /// ``` - /// Modular.to.push(MaterialPageRoute(builder: (context) => HomePage()),); - /// ``` - Future push(Route route); - /// Pop the current route off the navigator and navigate to a route. /// /// ``` @@ -67,19 +60,6 @@ abstract class IModularNavigator { {TO result, Object arguments}); - ///Replace the current route of the navigator that most tightly encloses - ///the given context by pushing the given route and then disposing - ///the previous route once the new route has finished animating in. - /// - /// ``` - /// Modular.to.pushReplacement( - /// MaterialPageRoute(builder: (context) => HomePage()) - /// ); - /// ``` - Future pushReplacement( - Route newRoute, - {TO result}); - /// Removes the current Route from the stack of routes. /// /// ``` diff --git a/flutter_modular/lib/src/routers/modular_navigator.dart b/flutter_modular/lib/src/routers/modular_navigator.dart index 6cf8b75c..7c2fc153 100644 --- a/flutter_modular/lib/src/routers/modular_navigator.dart +++ b/flutter_modular/lib/src/routers/modular_navigator.dart @@ -20,6 +20,13 @@ class ModularNavigator implements IModularNavigator { @override void pop([T result]) => navigator.pop(result); + @override + Future push(Route route) => navigator.push(route); + + @override + Future pushNamed(String routeName, {Object arguments}) => + routerDelegate.pushNamed(routeName, arguments: arguments); + @override Future popAndPushNamed( String routeName, @@ -35,13 +42,6 @@ class ModularNavigator implements IModularNavigator { void popUntil(bool Function(Route) predicate) => navigator.popUntil(predicate); - @override - Future push(Route route) => navigator.push(route); - - @override - Future pushNamed(String routeName, {Object arguments}) => - routerDelegate.pushNamed(routeName, arguments: arguments); - @override Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/lib/src/routers/modular_page.dart index 481d87ab..334310ca 100644 --- a/flutter_modular/lib/src/routers/modular_page.dart +++ b/flutter_modular/lib/src/routers/modular_page.dart @@ -3,12 +3,30 @@ import 'dart:async'; import 'package:flutter/material.dart'; import '../../flutter_modular.dart'; +final Map _allCompleters = {}; + class ModularPage extends Page { final ModularRouter router; - final popRoute = Completer(); - ModularPage({Key key, this.router}) - : super(key: key, name: router.path, arguments: router.args.data); + const ModularPage({Key key, this.router, String path, T arguments}) + : super(key: key, name: path, arguments: arguments); + + Future waitPop() { + if (_allCompleters.containsKey(hashCode)) { + return _allCompleters[hashCode].future; + } else { + _allCompleters[hashCode] = Completer(); + return _allCompleters[hashCode].future; + } + } + + void completePop(T result) { + if (_allCompleters.containsKey(hashCode) && + !_allCompleters[hashCode].isCompleted) { + _allCompleters[hashCode].complete(result); + _allCompleters.remove(hashCode); + } + } @override Route createRoute(BuildContext context) { diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index 39b705b2..3f748542 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -12,13 +12,13 @@ import '../utils/modular_arguments.dart'; typedef RouteBuilder = MaterialPageRoute Function( WidgetBuilder, RouteSettings); +typedef ModularChild = Widget Function( + BuildContext context, ModularArguments args); class ModularRouter { final ChildModule currentModule; - Completer popRoute = Completer(); - - ModularArguments args; + final ModularArguments args; final String path; @@ -43,7 +43,7 @@ class ModularRouter { /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final Widget Function(BuildContext context, ModularArguments args) child; + final ModularChild child; /// /// Paramenter name: [module] @@ -65,7 +65,7 @@ class ModularRouter { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - Map params; + final Map params; /// /// Paramenter name: [guards] @@ -179,9 +179,30 @@ class ModularRouter { final RouteBuilder routeGenerator; final String modulePath; final Duration duration; + final Map< + TransitionType, + PageRouteBuilder Function( + Widget Function(BuildContext, ModularArguments) builder, + ModularArguments args, + Duration transitionDuration, + RouteSettings settings, + )> transitions; - ModularRouter( + const ModularRouter( this.routerName, { + this.transitions = const { + TransitionType.fadeIn: fadeInTransition, + TransitionType.noTransition: noTransition, + TransitionType.rightToLeft: rightToLeft, + TransitionType.leftToRight: leftToRight, + TransitionType.upToDown: upToDown, + TransitionType.downToUp: downToUp, + TransitionType.scale: scale, + TransitionType.rotate: rotate, + TransitionType.size: size, + TransitionType.rightToLeftWithFade: rightToLeftWithFade, + TransitionType.leftToRightWithFade: leftToRightWithFade, + }, this.path = '/', this.args = const ModularArguments(), this.module, @@ -192,49 +213,18 @@ class ModularRouter { this.transition = TransitionType.defaultTransition, this.routeGenerator, this.customTransition, - this.popRoute, this.duration = const Duration(milliseconds: 300), this.modulePath = '/', - }) { - assert(routerName != null); - - popRoute = popRoute ?? Completer(); - - if (transition == null) throw ArgumentError('transition must not be null'); - if (transition == TransitionType.custom && customTransition == null) { - throw ArgumentError( - '[customTransition] required for transition type [TransitionType.custom]'); - } - if (module == null && child == null) { - throw ArgumentError('[module] or [child] must be provided'); - } - if (module != null && child != null) { - throw ArgumentError('You should provide only [module] or [child]'); - } - } - final Map< - TransitionType, - PageRouteBuilder Function( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, - Duration transitionDuration, - RouteSettings settings, - )> _transitions = { - TransitionType.fadeIn: fadeInTransition, - TransitionType.noTransition: noTransition, - TransitionType.rightToLeft: rightToLeft, - TransitionType.leftToRight: leftToRight, - TransitionType.upToDown: upToDown, - TransitionType.downToUp: downToUp, - TransitionType.scale: scale, - TransitionType.rotate: rotate, - TransitionType.size: size, - TransitionType.rightToLeftWithFade: rightToLeftWithFade, - TransitionType.leftToRightWithFade: leftToRightWithFade, - }; + }) : assert(routerName != null), + assert(transition != null), + assert((transition == TransitionType.custom && + customTransition != null) || + transition != TransitionType.custom && customTransition == null), + assert((module == null && child != null) || + (module != null && child == null)); ModularRouter copyWith( - {Widget Function(BuildContext context, ModularArguments args) child, + {ModularChild child, String routerName, ChildModule module, ChildModule currentModule, @@ -257,7 +247,6 @@ class ModularRouter { params: params ?? this.params, modulePath: modulePath ?? this.modulePath, path: path ?? this.path, - popRoute: popRoute ?? this.popRoute, guards: guards ?? this.guards, duration: duration ?? this.duration, routeGenerator: routeGenerator ?? this.routeGenerator, @@ -307,7 +296,7 @@ class ModularRouter { builder: widgetBuilder, ); } else { - var selectTransition = _transitions[transition]; + var selectTransition = transitions[transition]; return selectTransition(child, args, duration, settings); } } From 52f4d898a039877cd3ca0218f09628f7a7a6cd09 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 28 Oct 2020 01:13:26 -0300 Subject: [PATCH 16/71] remove not used methods --- flutter_modular/lib/src/modular_impl.dart | 1 - flutter_modular/lib/src/routers/modular_navigator.dart | 9 --------- 2 files changed, 10 deletions(-) diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index e734eb06..f0a040fc 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -3,7 +3,6 @@ import 'package:flutter/foundation.dart'; import '../flutter_modular.dart'; import 'delegates/modular_router_delegate.dart'; import 'interfaces/modular_interface.dart'; -import 'routers/modular_navigator.dart'; ChildModule _initialModule; diff --git a/flutter_modular/lib/src/routers/modular_navigator.dart b/flutter_modular/lib/src/routers/modular_navigator.dart index 7c2fc153..e67bcf76 100644 --- a/flutter_modular/lib/src/routers/modular_navigator.dart +++ b/flutter_modular/lib/src/routers/modular_navigator.dart @@ -20,9 +20,6 @@ class ModularNavigator implements IModularNavigator { @override void pop([T result]) => navigator.pop(result); - @override - Future push(Route route) => navigator.push(route); - @override Future pushNamed(String routeName, {Object arguments}) => routerDelegate.pushNamed(routeName, arguments: arguments); @@ -57,12 +54,6 @@ class ModularNavigator implements IModularNavigator { navigator.pushReplacementNamed(routeName, result: result, arguments: arguments); - @override - Future pushReplacement( - Route newRoute, - {TO result}) => - navigator.pushReplacement(newRoute, result: result); - @override String get modulePath => Modular.link.modulePath; From 2ea750d61390e462cad6d7869e8973d7dfd530c5 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 28 Oct 2020 01:20:59 -0300 Subject: [PATCH 17/71] added method navigate --- .../delegates/modular_router_delegate.dart | 7 +++ .../modular_navigator_interface.dart | 2 + .../lib/src/routers/modular_navigator.dart | 62 ------------------- 3 files changed, 9 insertions(+), 62 deletions(-) delete mode 100644 flutter_modular/lib/src/routers/modular_navigator.dart diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index ad45f8f7..5daa5237 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -53,6 +53,13 @@ class ModularRouterDelegate extends RouterDelegate rebuildPages(); } + @override + void navigate(String path, {arguments}) { + var router = parser.selectRoute(path); + router = router.copyWith(args: router?.args?.copyWith(data: arguments)); + setNewRoutePath(router); + } + bool _onPopPage(Route route, dynamic result) { if (!route.didPop(result) || route.isFirst) { return false; diff --git a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart index de03c40d..b55fad73 100644 --- a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart @@ -92,4 +92,6 @@ abstract class IModularNavigator { /// Modular.to.popUntil(ModalRoute.withName('/login')); /// ``` void popUntil(bool Function(Route) predicate); + + void navigate(String path, {dynamic arguments}); } diff --git a/flutter_modular/lib/src/routers/modular_navigator.dart b/flutter_modular/lib/src/routers/modular_navigator.dart deleted file mode 100644 index e67bcf76..00000000 --- a/flutter_modular/lib/src/routers/modular_navigator.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../flutter_modular.dart'; -import '../delegates/modular_router_delegate.dart'; -import '../interfaces/modular_navigator_interface.dart'; - -class ModularNavigator implements IModularNavigator { - final ModularRouterDelegate routerDelegate; - - ModularNavigator(this.routerDelegate); - - NavigatorState get navigator => routerDelegate.navigatorKey.currentState; - - @override - bool canPop() => navigator.canPop(); - - @override - Future maybePop([T result]) => - navigator.maybePop(result); - - @override - void pop([T result]) => navigator.pop(result); - - @override - Future pushNamed(String routeName, {Object arguments}) => - routerDelegate.pushNamed(routeName, arguments: arguments); - - @override - Future popAndPushNamed( - String routeName, - {TO result, - Object arguments}) => - navigator.popAndPushNamed( - routeName, - result: result, - arguments: arguments, - ); - - @override - void popUntil(bool Function(Route) predicate) => - navigator.popUntil(predicate); - - @override - Future pushNamedAndRemoveUntil( - String newRouteName, bool Function(Route) predicate, - {Object arguments}) => - navigator.pushNamedAndRemoveUntil(newRouteName, predicate, - arguments: arguments); - - @override - Future pushReplacementNamed( - String routeName, - {TO result, - Object arguments}) => - navigator.pushReplacementNamed(routeName, - result: result, arguments: arguments); - - @override - String get modulePath => Modular.link.modulePath; - - @override - String get path => Modular.link.path; -} From 1d29b9ae3a8fa894f9f2ec925e2602ed1c32f064 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 3 Nov 2020 15:14:13 -0300 Subject: [PATCH 18/71] implements navigator --- .../delegates/modular_router_delegate.dart | 46 ++++++++++++------- .../modular_navigator_interface.dart | 7 +++ .../lib/src/routers/modular_page.dart | 15 +++++- .../lib/src/routers/modular_router.dart | 32 ++++++------- .../no_animation_transition_delegate.dart | 36 +++++++++++++++ 5 files changed, 100 insertions(+), 36 deletions(-) create mode 100644 flutter_modular/lib/src/utils/no_animation_transition_delegate.dart diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index 5daa5237..a4faed9d 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -46,6 +46,7 @@ class ModularRouterDelegate extends RouterDelegate if (_pages.isEmpty) { _pages.add(page); } else { + _pages.last.completePop(null); _pages.last = page; } _router = router; @@ -61,7 +62,12 @@ class ModularRouterDelegate extends RouterDelegate } bool _onPopPage(Route route, dynamic result) { - if (!route.didPop(result) || route.isFirst) { + if (!route.didPop(result)) { + return false; + } + + if (route.isFirst) { + rebuildPages(); return false; } @@ -101,6 +107,7 @@ class ModularRouterDelegate extends RouterDelegate var router = parser.selectRoute(routeName); router = router.copyWith(args: router?.args?.copyWith(data: arguments)); final page = ModularPage( + key: UniqueKey(), router: router, ); _pages.add(page); @@ -116,16 +123,26 @@ class ModularRouterDelegate extends RouterDelegate var router = parser.selectRoute(routeName); router = router.copyWith(args: router?.args?.copyWith(data: arguments)); final page = ModularPage( + key: UniqueKey(), router: router, ); _pages.last.completePop(result); - _pages.last = page; rebuildPages(); return page.waitPop(); } + @override + Future popAndPushNamed( + String routeName, + {TO result, + Object arguments}) { + _pages.last.completePop(result); + _pages.removeLast(); + return pushNamed(routeName, arguments: arguments); + } + @override bool canPop() { return navigator.canPop(); @@ -138,31 +155,26 @@ class ModularRouterDelegate extends RouterDelegate @override void pop([T result]) => navigator.pop(result); - @override - Future popAndPushNamed( - String routeName, - {TO result, - Object arguments}) => - navigator.popAndPushNamed( - routeName, - result: result, - arguments: arguments, - ); - @override void popUntil(bool Function(Route) predicate) => navigator.popUntil(predicate); @override Future pushNamedAndRemoveUntil( - String newRouteName, bool Function(Route) predicate, - {Object arguments}) => - navigator.pushNamedAndRemoveUntil(newRouteName, predicate, - arguments: arguments); + String newRouteName, bool Function(Route) predicate, + {Object arguments}) { + popUntil(predicate); + return pushNamed(newRouteName, arguments: arguments); + } @override String get modulePath => _router.modulePath; @override String get path => _router.path; + + @override + Future push(Route route) { + return navigator.push(route); + } } diff --git a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart index b55fad73..7396f313 100644 --- a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart @@ -4,6 +4,13 @@ abstract class IModularNavigator { String get path; String get modulePath; + /// Navigate to a new screen. + /// + /// ``` + /// Modular.to.push(MaterialPageRoute(builder: (context) => HomePage()),); + /// ``` + Future push(Route route); + /// Pop the current route off the navigator and navigate to a route. /// /// ``` diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/lib/src/routers/modular_page.dart index 334310ca..2207da93 100644 --- a/flutter_modular/lib/src/routers/modular_page.dart +++ b/flutter_modular/lib/src/routers/modular_page.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; + import '../../flutter_modular.dart'; final Map _allCompleters = {}; @@ -8,8 +9,8 @@ final Map _allCompleters = {}; class ModularPage extends Page { final ModularRouter router; - const ModularPage({Key key, this.router, String path, T arguments}) - : super(key: key, name: path, arguments: arguments); + ModularPage({Key key, this.router}) + : super(key: key, name: router.path, arguments: router.args.data); Future waitPop() { if (_allCompleters.containsKey(hashCode)) { @@ -32,6 +33,16 @@ class ModularPage extends Page { Route createRoute(BuildContext context) { return router.getPageRoute(this); } + + // @override + // bool operator ==(Object o) { + // if (identical(this, o)) return true; + + // return o is ModularPage && o.router == router; + // } + + // @override + // int get hashCode => router.hashCode; } class ModularRoute extends Route { diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index 3f748542..0500a9a7 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -186,23 +186,22 @@ class ModularRouter { ModularArguments args, Duration transitionDuration, RouteSettings settings, - )> transitions; + )> transitions = { + TransitionType.fadeIn: fadeInTransition, + TransitionType.noTransition: noTransition, + TransitionType.rightToLeft: rightToLeft, + TransitionType.leftToRight: leftToRight, + TransitionType.upToDown: upToDown, + TransitionType.downToUp: downToUp, + TransitionType.scale: scale, + TransitionType.rotate: rotate, + TransitionType.size: size, + TransitionType.rightToLeftWithFade: rightToLeftWithFade, + TransitionType.leftToRightWithFade: leftToRightWithFade, + }; - const ModularRouter( + ModularRouter( this.routerName, { - this.transitions = const { - TransitionType.fadeIn: fadeInTransition, - TransitionType.noTransition: noTransition, - TransitionType.rightToLeft: rightToLeft, - TransitionType.leftToRight: leftToRight, - TransitionType.upToDown: upToDown, - TransitionType.downToUp: downToUp, - TransitionType.scale: scale, - TransitionType.rotate: rotate, - TransitionType.size: size, - TransitionType.rightToLeftWithFade: rightToLeftWithFade, - TransitionType.leftToRightWithFade: leftToRightWithFade, - }, this.path = '/', this.args = const ModularArguments(), this.module, @@ -272,9 +271,8 @@ class ModularRouter { Route getPageRoute(RouteSettings settings) { if (transition == TransitionType.custom && customTransition != null) { - return PageRouteBuilder( + return PageRouteBuilder( pageBuilder: (context, _, __) { - //return disposablePage; return child(context, args); }, settings: settings, diff --git a/flutter_modular/lib/src/utils/no_animation_transition_delegate.dart b/flutter_modular/lib/src/utils/no_animation_transition_delegate.dart new file mode 100644 index 00000000..9c0d7adb --- /dev/null +++ b/flutter_modular/lib/src/utils/no_animation_transition_delegate.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +class NoAnimationTransitionDelegate extends TransitionDelegate { + @override + Iterable resolve({ + List newPageRouteHistory, + Map + locationToExitingPageRoute, + Map> + pageRouteToPagelessRoutes, + }) { + final results = []; + + for (final pageRoute in newPageRouteHistory) { + if (pageRoute.isWaitingForEnteringDecision) { + pageRoute.markForAdd(); + } + results.add(pageRoute); + } + + for (final exitingPageRoute in locationToExitingPageRoute.values) { + if (exitingPageRoute.isWaitingForExitingDecision) { + exitingPageRoute.markForRemove(); + final pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute]; + if (pagelessRoutes != null) { + for (final pagelessRoute in pagelessRoutes) { + pagelessRoute.markForRemove(); + } + } + } + + results.add(exitingPageRoute); + } + return results; + } +} From 3f115cf7cb08e09a3a80ee5d45d8ba3416560748 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 3 Nov 2020 15:14:21 -0300 Subject: [PATCH 19/71] change version --- flutter_modular/CHANGELOG.md | 8 ++++++-- flutter_modular/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/flutter_modular/CHANGELOG.md b/flutter_modular/CHANGELOG.md index c8d876b1..7f8d946f 100644 --- a/flutter_modular/CHANGELOG.md +++ b/flutter_modular/CHANGELOG.md @@ -1,8 +1,12 @@ -## [3.0.0] - +## [2.5.0] - * Navigator 2.0 * Removed Modular.link * Refactor RouteGuard -* Added Modular.to.navigate and Modular.to.navigateByUrl +* Added Modular.to.navigate +* Added 3 new bind factories + 1. Bind.factory + 2. Bind.singleton + 3. Bind.lazySingleton ## [2.0.1] - 21 Sep 2020 * added onChangeRoute propety in RouterOutlet diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index ba706bb7..391d6e2b 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 2.0.0 +version: 2.5.0 homepage: https://github.com/Flutterando/modular environment: From 16cc6ea5288b1dae8cea83ca17d8dd2e28640c14 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 3 Nov 2020 15:14:36 -0300 Subject: [PATCH 20/71] added new constructors --- flutter_modular/lib/src/inject/bind.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/flutter_modular/lib/src/inject/bind.dart b/flutter_modular/lib/src/inject/bind.dart index 01374d6d..988a4b2e 100644 --- a/flutter_modular/lib/src/inject/bind.dart +++ b/flutter_modular/lib/src/inject/bind.dart @@ -13,6 +13,25 @@ class Bind { Bind(this.inject, {this.singleton = true, this.lazy = true}) : assert((singleton || lazy), r"'singleton' can't be false if 'lazy' is also false"); + + ///Bind a 'Singleton' class. + ///Built together with the module. + ///The instance will always be the same. + factory Bind.singleton(T Function(Inject i) inject) { + return Bind(inject, singleton: true, lazy: false); + } + + ///Bind a 'Lazy Singleton' class. + ///Built only when called the first time using Modular.get. + ///The instance will always be the same. + factory Bind.lazySingleton(T Function(Inject i) inject) { + return Bind(inject, singleton: true, lazy: true); + } + + ///Bind a factory. Always a new constructor when calling Modular.get + factory Bind.factory(T Function(Inject i) inject) { + return Bind(inject, singleton: false, lazy: false); + } } class BindInject extends Bind { From c350842cc130c64565f5d3ac15dbc5fe9ec852ff Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 3 Nov 2020 16:26:59 -0300 Subject: [PATCH 21/71] fix Modular.link --- flutter_modular/CHANGELOG.md | 2 +- .../delegates/modular_router_delegate.dart | 1 + flutter_modular/lib/src/inject/inject.dart | 32 ++------ .../lib/src/interfaces/modular_interface.dart | 10 +-- flutter_modular/lib/src/modular_impl.dart | 29 ++++--- .../lib/src/routers/modular_link.dart | 82 +++++++++++++++++++ 6 files changed, 114 insertions(+), 42 deletions(-) create mode 100644 flutter_modular/lib/src/routers/modular_link.dart diff --git a/flutter_modular/CHANGELOG.md b/flutter_modular/CHANGELOG.md index 7f8d946f..2b888f0c 100644 --- a/flutter_modular/CHANGELOG.md +++ b/flutter_modular/CHANGELOG.md @@ -1,6 +1,6 @@ ## [2.5.0] - * Navigator 2.0 -* Removed Modular.link +* Fixed Modular.link * Refactor RouteGuard * Added Modular.to.navigate * Added 3 new bind factories diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index a4faed9d..b53da473 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -25,6 +25,7 @@ class ModularRouterDelegate extends RouterDelegate @override ModularRouter get currentConfiguration => _router; + ModularRouter get lastPage => _pages.last.router; @override Widget build(BuildContext context) { diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/lib/src/inject/inject.dart index e54b446b..ae9594ad 100644 --- a/flutter_modular/lib/src/inject/inject.dart +++ b/flutter_modular/lib/src/inject/inject.dart @@ -8,12 +8,9 @@ class Inject { ///If you need specific access, do it through functions. @deprecated Map params = {}; - final String tag; final List typesInRequest; - Inject({this.params, this.tag, this.typesInRequest}); - - factory Inject.of() => Inject(tag: T.toString()); + Inject({this.params, this.typesInRequest}); B call({Map params, B defaultValue}) => get(params: params, defaultValue: defaultValue); @@ -21,33 +18,20 @@ class Inject { /// get injected dependency B get({Map params, B defaultValue}) { params ??= {}; - if (tag == null) { - return Modular.get( - params: params, - typesInRequest: typesInRequest, - defaultValue: defaultValue, - ); - } else { - return Modular.get( - module: tag, - params: params, - typesInRequest: typesInRequest, - defaultValue: defaultValue, - ); - } + return Modular.get( + params: params, + typesInRequest: typesInRequest, + defaultValue: defaultValue, + ); } void dispose() { - if (T.runtimeType.toString() == 'dynamic') { - Modular.dispose(); - } else { - Modular.dispose(tag); - } + Modular.dispose(); } } mixin InjectMixinBase { - final Inject _inject = Inject.of(); + final Inject _inject = Inject(); S get() => _inject.get(); } diff --git a/flutter_modular/lib/src/interfaces/modular_interface.dart b/flutter_modular/lib/src/interfaces/modular_interface.dart index afa1a4ee..c8106296 100644 --- a/flutter_modular/lib/src/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_interface.dart @@ -11,10 +11,10 @@ abstract class ModularInterface { IModularNavigator get to; IModularNavigator get link; - B get( - {Map params, - String module, - List typesInRequest, - B defaultValue}); + B get({ + Map params, + List typesInRequest, + B defaultValue, + }); void dispose([String moduleName]); } diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index f0a040fc..e4bf9748 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -62,7 +62,6 @@ class ModularImpl implements ModularInterface { @override B get( {Map params, - String module, List typesInRequest, B defaultValue}) { if (B.toString() == 'dynamic') { @@ -71,11 +70,20 @@ class ModularImpl implements ModularInterface { typesInRequest ??= []; - if (module != null) { - return _getInjectableObject(module, + B result; + + if (typesInRequest.isEmpty) { + final module = routerDelegate + .currentConfiguration.currentModule.runtimeType + .toString(); + result = _getInjectableObject(module, params: params, typesInRequest: typesInRequest); } + if (result != null) { + return result; + } + for (var key in injectMap.keys) { final value = _getInjectableObject(key, params: params, @@ -83,11 +91,12 @@ class ModularImpl implements ModularInterface { typesInRequest: typesInRequest, checkKey: false); if (value != null) { - return value; + result = value; + break; } } - if (defaultValue != null) { + if (result == null && defaultValue != null) { return defaultValue; } @@ -120,13 +129,9 @@ class ModularImpl implements ModularInterface { throw ModularError('not allow for dynamic values'); } - if (moduleName != null) { - _removeInjectableObject(moduleName); - } else { - for (var key in injectMap.keys) { - if (_removeInjectableObject(key)) { - break; - } + for (var key in injectMap.keys) { + if (_removeInjectableObject(key)) { + break; } } } diff --git a/flutter_modular/lib/src/routers/modular_link.dart b/flutter_modular/lib/src/routers/modular_link.dart new file mode 100644 index 00000000..913fe4f5 --- /dev/null +++ b/flutter_modular/lib/src/routers/modular_link.dart @@ -0,0 +1,82 @@ +import 'package:flutter/widgets.dart'; + +import '../delegates/modular_router_delegate.dart'; + +import '../interfaces/modular_navigator_interface.dart'; + +class ModularLink implements IModularNavigator { + final ModularRouterDelegate delegate; + + ModularLink(this.delegate); + + @override + bool canPop() => delegate.canPop(); + + @override + Future push(Route route) => delegate.push(route); + + @override + Future maybePop([T result]) => + delegate.maybePop(result); + + @override + void pop([T result]) => delegate.pop(result); + + @override + void popUntil(bool Function(Route) predicate) => + delegate.popUntil(predicate); + + @override + String get modulePath => delegate.lastPage.modulePath; + @override + String get path => delegate.lastPage.path; + + @override + void navigate(String path, {arguments}) => delegate.navigate( + modulePath + path, + arguments: arguments, + ); + + @override + Future popAndPushNamed( + String routeName, + {TO result, + Object arguments}) { + return delegate.popAndPushNamed( + modulePath + routeName, + result: result, + arguments: arguments, + ); + } + + @override + Future pushNamed(String routeName, {Object arguments}) { + return delegate.pushNamed( + modulePath + routeName, + arguments: arguments, + ); + } + + @override + Future pushNamedAndRemoveUntil( + String newRouteName, bool Function(Route) predicate, + {Object arguments}) { + return delegate.pushNamedAndRemoveUntil( + modulePath + newRouteName, + predicate, + arguments: arguments, + ); + } + + @override + Future pushReplacementNamed( + String routeName, + {TO result, + Object arguments}) { + return delegate.pushReplacementNamed( + modulePath + routeName, + result: result, + arguments: arguments, + ); + } +} From 7cab9e324626c4289c4d9f092ef1f1a4c4a3c110 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 3 Nov 2020 16:32:40 -0300 Subject: [PATCH 22/71] change version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 391d6e2b..5645501f 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 2.5.0 +version: 2.5.0-alpha.1 homepage: https://github.com/Flutterando/modular environment: From b6a4e08629200241c7e55b77f7dc7027df1fc1b3 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 3 Nov 2020 17:33:22 -0300 Subject: [PATCH 23/71] private variables --- flutter_modular/lib/src/modular_base.dart | 8 ++++---- modular.code-workspace | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index 56b0d2e2..a935fa88 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -11,16 +11,16 @@ final _navigatorKey = GlobalKey(); final Map _injectMap = {}; -final routeInformationParser = ModularRouteInformationParser(); -final routerDelegate = ModularRouterDelegate( +final _routeInformationParser = ModularRouteInformationParser(); +final _routerDelegate = ModularRouterDelegate( _navigatorKey, - routeInformationParser, + _routeInformationParser, _injectMap, ); // ignore: non_constant_identifier_names final ModularInterface Modular = ModularImpl( - routerDelegate: routerDelegate, + routerDelegate: _routerDelegate, injectMap: _injectMap, ); diff --git a/modular.code-workspace b/modular.code-workspace index 0f8b5353..15c504b3 100644 --- a/modular.code-workspace +++ b/modular.code-workspace @@ -7,5 +7,7 @@ "path": "modular_codegen" } ], - "settings": {} + "settings": { + "dart.flutterSdkPath": "/Users/jacobmoura/fvm/versions/1.22.1" + } } \ No newline at end of file From b2f9a16633b88c4cd6aab0199055f9424f21c617 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Thu, 5 Nov 2020 12:49:17 -0300 Subject: [PATCH 24/71] fix inject --- flutter_modular/lib/src/modular_base.dart | 4 ++-- flutter_modular/lib/src/modular_impl.dart | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index a935fa88..94f80502 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -54,8 +54,8 @@ extension ModularExtension on MaterialApp { shortcuts: shortcuts, actions: actions, restorationScopeId: restorationScopeId, - routeInformationParser: routeInformationParser, - routerDelegate: routerDelegate, + routeInformationParser: _routeInformationParser, + routerDelegate: _routerDelegate, ); return app; diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index e4bf9748..6a1abee1 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -91,8 +91,7 @@ class ModularImpl implements ModularInterface { typesInRequest: typesInRequest, checkKey: false); if (value != null) { - result = value; - break; + return value; } } @@ -116,9 +115,9 @@ class ModularImpl implements ModularInterface { } else if (injectMap.containsKey(tag)) { value = injectMap[tag].getBind(params, typesInRequest: typesInRequest); } - if (value == null && !disableError) { - throw ModularError('${B.toString()} not found in module $tag'); - } + // if (value == null && !disableError) { + // throw ModularError('${B.toString()} not found in module $tag'); + // } return value; } From c4bff9011d48bdf6d3a4d88ea4ca45994403e82f Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Thu, 5 Nov 2020 12:49:41 -0300 Subject: [PATCH 25/71] change versnion --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 5645501f..1ccd969d 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 2.5.0-alpha.1 +version: 2.5.0-alpha.2 homepage: https://github.com/Flutterando/modular environment: From 45825d0935d52f1a48bf0ca6f064043773586a43 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Thu, 5 Nov 2020 20:56:17 -0300 Subject: [PATCH 26/71] change versnion --- flutter_modular/lib/src/modular_base.dart | 4 ++-- flutter_modular/pubspec.yaml | 2 +- modular.code-workspace | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index 94f80502..bca9818d 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -28,7 +28,7 @@ extension ModularExtension on MaterialApp { MaterialApp modular() { final app = MaterialApp.router( key: key, - scaffoldMessengerKey: scaffoldMessengerKey, + //scaffoldMessengerKey: scaffoldMessengerKey, routeInformationProvider: routeInformationProvider, backButtonDispatcher: backButtonDispatcher, builder: builder, @@ -53,7 +53,7 @@ extension ModularExtension on MaterialApp { debugShowCheckedModeBanner: debugShowCheckedModeBanner, shortcuts: shortcuts, actions: actions, - restorationScopeId: restorationScopeId, + //restorationScopeId: restorationScopeId, routeInformationParser: _routeInformationParser, routerDelegate: _routerDelegate, ); diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 1ccd969d..856b9bc1 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 2.5.0-alpha.2 +version: 2.5.0-alpha.3 homepage: https://github.com/Flutterando/modular environment: diff --git a/modular.code-workspace b/modular.code-workspace index 15c504b3..0e66ce0b 100644 --- a/modular.code-workspace +++ b/modular.code-workspace @@ -8,6 +8,6 @@ } ], "settings": { - "dart.flutterSdkPath": "/Users/jacobmoura/fvm/versions/1.22.1" + "dart.flutterSdkPath": "/Users/jacobmoura/fvm/versions/stable" } } \ No newline at end of file From 4a535cdfcd801733ba9f5d5c7382f33c2b36c865 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 6 Nov 2020 17:42:55 -0300 Subject: [PATCH 27/71] added Future in navigate --- .../modular_route_information_parser.dart | 29 +++++++++++++++++-- .../delegates/modular_router_delegate.dart | 10 +++---- .../lib/src/interfaces/route_guard.dart | 10 ++----- flutter_modular/lib/src/modular_impl.dart | 9 +----- .../lib/src/routers/modular_router.dart | 13 +-------- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart index c98c3df7..cc53b973 100644 --- a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart @@ -8,7 +8,7 @@ class ModularRouteInformationParser Future parseRouteInformation( RouteInformation routeInformation) async { final path = routeInformation.location; - final route = selectRoute(path); + final route = await selectRoute(path); return route; } @@ -137,11 +137,34 @@ class ModularRouteInformationParser return router; } - ModularRouter selectRoute(String path, [ChildModule module]) { + Future selectRoute(String path, [ChildModule module]) async { if (path.isEmpty) { throw Exception("Router can not be empty"); } final route = _searchInModule(module ?? Modular.initialModule, "", path); - return route; + return canActivate(path, route); + } + + Future canActivate(String path, ModularRouter router) async { + if (router == null) { + return null; + } + + if (router.guards?.isNotEmpty == true) { + for (var guard in router.guards) { + try { + final result = await guard.canActivate(path, router); + if (!result) { + print('$path is NOT ACTIVATE'); + return null; + } + // ignore: avoid_catches_without_on_clauses + } catch (e) { + throw ModularError( + 'RouteGuard error. Check ($path) in ${router.currentModule.runtimeType}'); + } + } + } + return router; } } diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index b53da473..34700b37 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -56,8 +56,8 @@ class ModularRouterDelegate extends RouterDelegate } @override - void navigate(String path, {arguments}) { - var router = parser.selectRoute(path); + Future navigate(String path, {arguments}) async { + var router = await parser.selectRoute(path); router = router.copyWith(args: router?.args?.copyWith(data: arguments)); setNewRoutePath(router); } @@ -105,7 +105,7 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamed(String routeName, {Object arguments}) async { - var router = parser.selectRoute(routeName); + var router = await parser.selectRoute(routeName); router = router.copyWith(args: router?.args?.copyWith(data: arguments)); final page = ModularPage( key: UniqueKey(), @@ -120,8 +120,8 @@ class ModularRouterDelegate extends RouterDelegate Future pushReplacementNamed( String routeName, {TO result, - Object arguments}) { - var router = parser.selectRoute(routeName); + Object arguments}) async { + var router = await parser.selectRoute(routeName); router = router.copyWith(args: router?.args?.copyWith(data: arguments)); final page = ModularPage( key: UniqueKey(), diff --git a/flutter_modular/lib/src/interfaces/route_guard.dart b/flutter_modular/lib/src/interfaces/route_guard.dart index fc97d843..a831ca51 100644 --- a/flutter_modular/lib/src/interfaces/route_guard.dart +++ b/flutter_modular/lib/src/interfaces/route_guard.dart @@ -1,10 +1,6 @@ //ignore:one_member_abstracts -abstract class GuardExecutor { - void onGuarded(String path, {bool isActive}); -} - -abstract class RouteGuard { - bool canActivate(String url); +import '../routers/modular_router.dart'; - List get executors; +mixin RouteGuard { + Future canActivate(String path, ModularRouter router); } diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index 6a1abee1..48f6282b 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -86,10 +86,7 @@ class ModularImpl implements ModularInterface { for (var key in injectMap.keys) { final value = _getInjectableObject(key, - params: params, - disableError: true, - typesInRequest: typesInRequest, - checkKey: false); + params: params, typesInRequest: typesInRequest, checkKey: false); if (value != null) { return value; } @@ -105,7 +102,6 @@ class ModularImpl implements ModularInterface { B _getInjectableObject( String tag, { Map params, - bool disableError = false, List typesInRequest, bool checkKey = true, }) { @@ -115,9 +111,6 @@ class ModularImpl implements ModularInterface { } else if (injectMap.containsKey(tag)) { value = injectMap[tag].getBind(params, typesInRequest: typesInRequest); } - // if (value == null && !disableError) { - // throw ModularError('${B.toString()} not found in module $tag'); - // } return value; } diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index 0500a9a7..714588de 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -82,7 +82,7 @@ class ModularRouter { /// ```dart ///class MyGuard implements RouteGuard { /// @override - /// bool canActivate(String url) { + /// Future canActivate(String url, ModularRouter router) { /// if (url != '/admin'){ /// // Return `true` to allow access /// return true; @@ -92,17 +92,6 @@ class ModularRouter { /// } /// } ///} - ///To use your RouteGuard in a route, pass it to the guards parameter: - /// - ///@override - ///List get routers => [ - /// ModularRouter('/', module: HomeModule()), - /// ModularRouter( - /// '/admin', - /// module: AdminModule(), - /// guards: [MyGuard()], - /// ), - ///]; /// ``` /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// From 2076a7c0e607d3eca4edf6a2e7aef46091d4fdd6 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 22 Nov 2020 22:24:18 -0300 Subject: [PATCH 28/71] null safety --- .../abstract_router_test.dart | 0 .../{test => .backup}/app/app_bloc.dart | 0 .../{test => .backup}/app/app_module.dart | 2 +- .../app/app_module_test_modular.dart | 0 .../{test => .backup}/app/app_widget.dart | 0 .../{test => .backup}/app/guard/guard.dart | 0 .../modules/forbidden/forbidden_widget.dart | 0 .../app/modules/home/home_bloc.dart | 0 .../app/modules/home/home_module.dart | 8 +- .../home/home_module_test_modular.dart | 0 .../app/modules/home/home_widget.dart | 0 .../app/modules/product/product_bloc.dart | 0 .../app/modules/product/product_module.dart | 0 .../product/product_module_test_modular.dart | 0 .../app/modules/product/product_widget.dart | 0 .../app/shared/app_info.state.dart | 0 .../app/shared/ilocal_repository.dart | 0 .../app/shared/local_mock.dart | 0 .../app/shared/local_storage_shared.dart | 0 .../{test => .backup}/bind_test.dart | 0 .../{test => .backup}/modular_app_test.dart | 0 .../modular_extension_test.dart | 0 .../{test => .backup}/modular_impl.dart | 0 .../modular_inject_test.dart | 0 .../modular_module_test_interface_test.dart | 0 .../modular_stack_overflow_test.dart | 0 .../{test => .backup}/modular_test.dart | 0 .../{test => .backup}/modular_test_test.dart | 0 .../modular_widget_test.dart | 0 .../{test => .backup}/new_route_test.dart | 0 .../routers/router_test.dart | 0 .../transition/transitions_test.dart | 0 .../modular_route_information_parser.dart | 51 ++++---- .../delegates/modular_router_delegate.dart | 40 +++---- flutter_modular/lib/src/inject/bind.dart | 4 + flutter_modular/lib/src/inject/inject.dart | 11 +- .../lib/src/interfaces/child_module.dart | 14 ++- .../lib/src/interfaces/modular_interface.dart | 10 +- .../modular_navigator_interface.dart | 10 +- flutter_modular/lib/src/modular_base.dart | 4 +- flutter_modular/lib/src/modular_impl.dart | 47 ++++---- .../lib/src/routers/modular_link.dart | 22 ++-- .../lib/src/routers/modular_page.dart | 14 +-- .../lib/src/routers/modular_router.dart | 99 +++++++++------- .../lib/src/test/modular_test_interface.dart | 24 ++-- flutter_modular/lib/src/test/utils_test.dart | 15 +-- .../lib/src/transitions/page_transition.dart | 10 +- .../lib/src/transitions/transitions.dart | 44 +++---- .../lib/src/utils/modular_arguments.dart | 12 +- .../no_animation_transition_delegate.dart | 36 ------ .../lib/src/widgets/modular_app.dart | 4 +- .../lib/src/widgets/modular_state.dart | 2 +- .../lib/src/widgets/router_outlet.dart | 112 ++++++++++-------- .../lib/src/widgets/widget_module.dart | 14 ++- flutter_modular/pubspec.yaml | 2 +- modular.code-workspace | 2 +- 56 files changed, 310 insertions(+), 303 deletions(-) rename flutter_modular/{test => .backup}/abstract_router_test.dart (100%) rename flutter_modular/{test => .backup}/app/app_bloc.dart (100%) rename flutter_modular/{test => .backup}/app/app_module.dart (98%) rename flutter_modular/{test => .backup}/app/app_module_test_modular.dart (100%) rename flutter_modular/{test => .backup}/app/app_widget.dart (100%) rename flutter_modular/{test => .backup}/app/guard/guard.dart (100%) rename flutter_modular/{test => .backup}/app/modules/forbidden/forbidden_widget.dart (100%) rename flutter_modular/{test => .backup}/app/modules/home/home_bloc.dart (100%) rename flutter_modular/{test => .backup}/app/modules/home/home_module.dart (88%) rename flutter_modular/{test => .backup}/app/modules/home/home_module_test_modular.dart (100%) rename flutter_modular/{test => .backup}/app/modules/home/home_widget.dart (100%) rename flutter_modular/{test => .backup}/app/modules/product/product_bloc.dart (100%) rename flutter_modular/{test => .backup}/app/modules/product/product_module.dart (100%) rename flutter_modular/{test => .backup}/app/modules/product/product_module_test_modular.dart (100%) rename flutter_modular/{test => .backup}/app/modules/product/product_widget.dart (100%) rename flutter_modular/{test => .backup}/app/shared/app_info.state.dart (100%) rename flutter_modular/{test => .backup}/app/shared/ilocal_repository.dart (100%) rename flutter_modular/{test => .backup}/app/shared/local_mock.dart (100%) rename flutter_modular/{test => .backup}/app/shared/local_storage_shared.dart (100%) rename flutter_modular/{test => .backup}/bind_test.dart (100%) rename flutter_modular/{test => .backup}/modular_app_test.dart (100%) rename flutter_modular/{test => .backup}/modular_extension_test.dart (100%) rename flutter_modular/{test => .backup}/modular_impl.dart (100%) rename flutter_modular/{test => .backup}/modular_inject_test.dart (100%) rename flutter_modular/{test => .backup}/modular_module_test_interface_test.dart (100%) rename flutter_modular/{test => .backup}/modular_stack_overflow_test.dart (100%) rename flutter_modular/{test => .backup}/modular_test.dart (100%) rename flutter_modular/{test => .backup}/modular_test_test.dart (100%) rename flutter_modular/{test => .backup}/modular_widget_test.dart (100%) rename flutter_modular/{test => .backup}/new_route_test.dart (100%) rename flutter_modular/{test => .backup}/routers/router_test.dart (100%) rename flutter_modular/{test => .backup}/transition/transitions_test.dart (100%) delete mode 100644 flutter_modular/lib/src/utils/no_animation_transition_delegate.dart diff --git a/flutter_modular/test/abstract_router_test.dart b/flutter_modular/.backup/abstract_router_test.dart similarity index 100% rename from flutter_modular/test/abstract_router_test.dart rename to flutter_modular/.backup/abstract_router_test.dart diff --git a/flutter_modular/test/app/app_bloc.dart b/flutter_modular/.backup/app/app_bloc.dart similarity index 100% rename from flutter_modular/test/app/app_bloc.dart rename to flutter_modular/.backup/app/app_bloc.dart diff --git a/flutter_modular/test/app/app_module.dart b/flutter_modular/.backup/app/app_module.dart similarity index 98% rename from flutter_modular/test/app/app_module.dart rename to flutter_modular/.backup/app/app_module.dart index 00cb826a..3462c93d 100644 --- a/flutter_modular/test/app/app_module.dart +++ b/flutter_modular/.backup/app/app_module.dart @@ -23,7 +23,7 @@ class AppModule extends MainModule { transition: TransitionType.fadeIn, ), ModularRouter( - "/", + "/home", module: HomeModule(), transition: TransitionType.fadeIn, ), diff --git a/flutter_modular/test/app/app_module_test_modular.dart b/flutter_modular/.backup/app/app_module_test_modular.dart similarity index 100% rename from flutter_modular/test/app/app_module_test_modular.dart rename to flutter_modular/.backup/app/app_module_test_modular.dart diff --git a/flutter_modular/test/app/app_widget.dart b/flutter_modular/.backup/app/app_widget.dart similarity index 100% rename from flutter_modular/test/app/app_widget.dart rename to flutter_modular/.backup/app/app_widget.dart diff --git a/flutter_modular/test/app/guard/guard.dart b/flutter_modular/.backup/app/guard/guard.dart similarity index 100% rename from flutter_modular/test/app/guard/guard.dart rename to flutter_modular/.backup/app/guard/guard.dart diff --git a/flutter_modular/test/app/modules/forbidden/forbidden_widget.dart b/flutter_modular/.backup/app/modules/forbidden/forbidden_widget.dart similarity index 100% rename from flutter_modular/test/app/modules/forbidden/forbidden_widget.dart rename to flutter_modular/.backup/app/modules/forbidden/forbidden_widget.dart diff --git a/flutter_modular/test/app/modules/home/home_bloc.dart b/flutter_modular/.backup/app/modules/home/home_bloc.dart similarity index 100% rename from flutter_modular/test/app/modules/home/home_bloc.dart rename to flutter_modular/.backup/app/modules/home/home_bloc.dart diff --git a/flutter_modular/test/app/modules/home/home_module.dart b/flutter_modular/.backup/app/modules/home/home_module.dart similarity index 88% rename from flutter_modular/test/app/modules/home/home_module.dart rename to flutter_modular/.backup/app/modules/home/home_module.dart index b5a5957e..47bb8995 100644 --- a/flutter_modular/test/app/modules/home/home_module.dart +++ b/flutter_modular/.backup/app/modules/home/home_module.dart @@ -3,6 +3,7 @@ import 'package:flutter_modular/flutter_modular.dart'; import '../../app_bloc.dart'; import '../../shared/app_info.state.dart'; +import '../forbidden/forbidden_widget.dart'; import 'home_bloc.dart'; import 'home_widget.dart'; @@ -19,8 +20,13 @@ class HomeModule extends ChildModule { ModularRouter( "/", child: (_, args) => HomeWidget(), - transition: TransitionType.fadeIn, + children: [ + ModularRouter('/', child: (context, args) => ForbiddenWidget()), + ModularRouter('/product', + child: (context, args) => ForbiddenWidget()), + ], ), + // ModularRouter( // "/forbidden2", // child: (_, args) => ForbiddenWidget(), diff --git a/flutter_modular/test/app/modules/home/home_module_test_modular.dart b/flutter_modular/.backup/app/modules/home/home_module_test_modular.dart similarity index 100% rename from flutter_modular/test/app/modules/home/home_module_test_modular.dart rename to flutter_modular/.backup/app/modules/home/home_module_test_modular.dart diff --git a/flutter_modular/test/app/modules/home/home_widget.dart b/flutter_modular/.backup/app/modules/home/home_widget.dart similarity index 100% rename from flutter_modular/test/app/modules/home/home_widget.dart rename to flutter_modular/.backup/app/modules/home/home_widget.dart diff --git a/flutter_modular/test/app/modules/product/product_bloc.dart b/flutter_modular/.backup/app/modules/product/product_bloc.dart similarity index 100% rename from flutter_modular/test/app/modules/product/product_bloc.dart rename to flutter_modular/.backup/app/modules/product/product_bloc.dart diff --git a/flutter_modular/test/app/modules/product/product_module.dart b/flutter_modular/.backup/app/modules/product/product_module.dart similarity index 100% rename from flutter_modular/test/app/modules/product/product_module.dart rename to flutter_modular/.backup/app/modules/product/product_module.dart diff --git a/flutter_modular/test/app/modules/product/product_module_test_modular.dart b/flutter_modular/.backup/app/modules/product/product_module_test_modular.dart similarity index 100% rename from flutter_modular/test/app/modules/product/product_module_test_modular.dart rename to flutter_modular/.backup/app/modules/product/product_module_test_modular.dart diff --git a/flutter_modular/test/app/modules/product/product_widget.dart b/flutter_modular/.backup/app/modules/product/product_widget.dart similarity index 100% rename from flutter_modular/test/app/modules/product/product_widget.dart rename to flutter_modular/.backup/app/modules/product/product_widget.dart diff --git a/flutter_modular/test/app/shared/app_info.state.dart b/flutter_modular/.backup/app/shared/app_info.state.dart similarity index 100% rename from flutter_modular/test/app/shared/app_info.state.dart rename to flutter_modular/.backup/app/shared/app_info.state.dart diff --git a/flutter_modular/test/app/shared/ilocal_repository.dart b/flutter_modular/.backup/app/shared/ilocal_repository.dart similarity index 100% rename from flutter_modular/test/app/shared/ilocal_repository.dart rename to flutter_modular/.backup/app/shared/ilocal_repository.dart diff --git a/flutter_modular/test/app/shared/local_mock.dart b/flutter_modular/.backup/app/shared/local_mock.dart similarity index 100% rename from flutter_modular/test/app/shared/local_mock.dart rename to flutter_modular/.backup/app/shared/local_mock.dart diff --git a/flutter_modular/test/app/shared/local_storage_shared.dart b/flutter_modular/.backup/app/shared/local_storage_shared.dart similarity index 100% rename from flutter_modular/test/app/shared/local_storage_shared.dart rename to flutter_modular/.backup/app/shared/local_storage_shared.dart diff --git a/flutter_modular/test/bind_test.dart b/flutter_modular/.backup/bind_test.dart similarity index 100% rename from flutter_modular/test/bind_test.dart rename to flutter_modular/.backup/bind_test.dart diff --git a/flutter_modular/test/modular_app_test.dart b/flutter_modular/.backup/modular_app_test.dart similarity index 100% rename from flutter_modular/test/modular_app_test.dart rename to flutter_modular/.backup/modular_app_test.dart diff --git a/flutter_modular/test/modular_extension_test.dart b/flutter_modular/.backup/modular_extension_test.dart similarity index 100% rename from flutter_modular/test/modular_extension_test.dart rename to flutter_modular/.backup/modular_extension_test.dart diff --git a/flutter_modular/test/modular_impl.dart b/flutter_modular/.backup/modular_impl.dart similarity index 100% rename from flutter_modular/test/modular_impl.dart rename to flutter_modular/.backup/modular_impl.dart diff --git a/flutter_modular/test/modular_inject_test.dart b/flutter_modular/.backup/modular_inject_test.dart similarity index 100% rename from flutter_modular/test/modular_inject_test.dart rename to flutter_modular/.backup/modular_inject_test.dart diff --git a/flutter_modular/test/modular_module_test_interface_test.dart b/flutter_modular/.backup/modular_module_test_interface_test.dart similarity index 100% rename from flutter_modular/test/modular_module_test_interface_test.dart rename to flutter_modular/.backup/modular_module_test_interface_test.dart diff --git a/flutter_modular/test/modular_stack_overflow_test.dart b/flutter_modular/.backup/modular_stack_overflow_test.dart similarity index 100% rename from flutter_modular/test/modular_stack_overflow_test.dart rename to flutter_modular/.backup/modular_stack_overflow_test.dart diff --git a/flutter_modular/test/modular_test.dart b/flutter_modular/.backup/modular_test.dart similarity index 100% rename from flutter_modular/test/modular_test.dart rename to flutter_modular/.backup/modular_test.dart diff --git a/flutter_modular/test/modular_test_test.dart b/flutter_modular/.backup/modular_test_test.dart similarity index 100% rename from flutter_modular/test/modular_test_test.dart rename to flutter_modular/.backup/modular_test_test.dart diff --git a/flutter_modular/test/modular_widget_test.dart b/flutter_modular/.backup/modular_widget_test.dart similarity index 100% rename from flutter_modular/test/modular_widget_test.dart rename to flutter_modular/.backup/modular_widget_test.dart diff --git a/flutter_modular/test/new_route_test.dart b/flutter_modular/.backup/new_route_test.dart similarity index 100% rename from flutter_modular/test/new_route_test.dart rename to flutter_modular/.backup/new_route_test.dart diff --git a/flutter_modular/test/routers/router_test.dart b/flutter_modular/.backup/routers/router_test.dart similarity index 100% rename from flutter_modular/test/routers/router_test.dart rename to flutter_modular/.backup/routers/router_test.dart diff --git a/flutter_modular/test/transition/transitions_test.dart b/flutter_modular/.backup/transition/transitions_test.dart similarity index 100% rename from flutter_modular/test/transition/transitions_test.dart rename to flutter_modular/.backup/transition/transitions_test.dart diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart index cc53b973..088e1c86 100644 --- a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart @@ -7,7 +7,7 @@ class ModularRouteInformationParser @override Future parseRouteInformation( RouteInformation routeInformation) async { - final path = routeInformation.location; + final path = routeInformation.location ?? '/'; final route = await selectRoute(path); return route; } @@ -17,7 +17,7 @@ class ModularRouteInformationParser return RouteInformation(location: router.path); } - ModularRouter _searchInModule( + ModularRouter? _searchInModule( ChildModule module, String routerName, String path) { path = "/$path".replaceAll('//', '/'); final routers = @@ -25,7 +25,7 @@ class ModularRouteInformationParser routers.sort((preview, actual) { return preview.routerName.contains('/:') ? 1 : 0; }); - for (var route in routers) { + for (ModularRouter? route in routers) { route = _searchRoute(route, routerName, path); if (route != null) { return route; @@ -34,23 +34,23 @@ class ModularRouteInformationParser return null; } - ModularRouter _normalizeRoute( + ModularRouter? _normalizeRoute( ModularRouter route, String routerName, String path) { - ModularRouter router; + ModularRouter? router; if (routerName == path || routerName == "$path/") { - router = route.module.routers[0]; + router = route.module!.routers[0]; if (router.module != null) { var _routerName = (routerName + route.routerName).replaceFirst('//', '/'); - router = _searchInModule(route.module, _routerName, path); + router = _searchInModule(route.module!, _routerName, path); } } else { - router = _searchInModule(route.module, routerName, path); + router = _searchInModule(route.module!, routerName, path); } return router; } - ModularRouter _searchRoute( + ModularRouter? _searchRoute( ModularRouter route, String routerName, String path) { final tempRouteName = (routerName + route.routerName).replaceFirst('//', '/'); @@ -71,13 +71,15 @@ class ModularRouteInformationParser customTransition: route.customTransition, ); } - Modular.bindModule(route.module, path); + if (route.module != null) { + Modular.bindModule(route.module!, path); + } return router; } } else { - route = _parseUrlParams(route, tempRouteName, path); - if (route != null) { - Modular.bindModule(route.currentModule, path); + var parseRoute = _parseUrlParams(route, tempRouteName, path); + if (parseRoute != null && parseRoute.currentModule != null) { + Modular.bindModule(parseRoute.currentModule!, path); return route.copyWith(path: path); } } @@ -95,7 +97,7 @@ class ModularRouteInformationParser return newUrl.join("/"); } - ModularRouter _parseUrlParams( + ModularRouter? _parseUrlParams( ModularRouter router, String routeNamed, String path) { if (routeNamed.split('/').length != path.split('/').length) { return null; @@ -121,42 +123,41 @@ class ModularRouteInformationParser if (pathParts[paramPos].isNotEmpty) { params[paramName] = pathParts[paramPos]; routeNamed = - routeNamed.replaceFirst(routePart, params[paramName]); + routeNamed.replaceFirst(routePart, params[paramName]!); } } paramPos++; } - params = routeNamed != path ? null : params; - return router.copyWith(args: router.args.copyWith(params: params)); + var _params = routeNamed != path ? null : params; + return router.copyWith(args: router.args!.copyWith(params: _params)); } - return router.copyWith(args: router.args.copyWith(params: null)); + return router.copyWith(args: router.args!.copyWith(params: null)); } return router; } - Future selectRoute(String path, [ChildModule module]) async { + Future selectRoute(String path, [ChildModule? module]) async { if (path.isEmpty) { throw Exception("Router can not be empty"); } - final route = _searchInModule(module ?? Modular.initialModule, "", path); + var route = _searchInModule(module ?? Modular.initialModule, "", path); return canActivate(path, route); } - Future canActivate(String path, ModularRouter router) async { + Future canActivate(String path, ModularRouter? router) async { if (router == null) { - return null; + throw ModularError('Route not found'); } if (router.guards?.isNotEmpty == true) { - for (var guard in router.guards) { + for (var guard in router.guards!) { try { final result = await guard.canActivate(path, router); if (!result) { - print('$path is NOT ACTIVATE'); - return null; + throw ModularError('$path is NOT ACTIVATE'); } // ignore: avoid_catches_without_on_clauses } catch (e) { diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/lib/src/delegates/modular_router_delegate.dart index 34700b37..62eaa047 100644 --- a/flutter_modular/lib/src/delegates/modular_router_delegate.dart +++ b/flutter_modular/lib/src/delegates/modular_router_delegate.dart @@ -17,14 +17,14 @@ class ModularRouterDelegate extends RouterDelegate ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); - NavigatorState get navigator => navigatorKey.currentState; + NavigatorState get navigator => navigatorKey.currentState!; - ModularRouter _router; + ModularRouter? _router; List _pages = []; @override - ModularRouter get currentConfiguration => _router; + ModularRouter? get currentConfiguration => _router; ModularRouter get lastPage => _pages.last.router; @override @@ -58,7 +58,7 @@ class ModularRouterDelegate extends RouterDelegate @override Future navigate(String path, {arguments}) async { var router = await parser.selectRoute(path); - router = router.copyWith(args: router?.args?.copyWith(data: arguments)); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); setNewRoutePath(router); } @@ -104,25 +104,25 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamed(String routeName, - {Object arguments}) async { + {Object? arguments}) async { var router = await parser.selectRoute(routeName); - router = router.copyWith(args: router?.args?.copyWith(data: arguments)); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); final page = ModularPage( key: UniqueKey(), router: router, ); _pages.add(page); rebuildPages(); - return page.waitPop(); + return await page.waitPop(); } @override Future pushReplacementNamed( String routeName, - {TO result, - Object arguments}) async { + {TO? result, + Object? arguments}) async { var router = await parser.selectRoute(routeName); - router = router.copyWith(args: router?.args?.copyWith(data: arguments)); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); final page = ModularPage( key: UniqueKey(), router: router, @@ -131,17 +131,17 @@ class ModularRouterDelegate extends RouterDelegate _pages.last.completePop(result); _pages.last = page; rebuildPages(); - return page.waitPop(); + return await page.waitPop(); } @override Future popAndPushNamed( String routeName, - {TO result, - Object arguments}) { + {TO? result, + Object? arguments}) async { _pages.last.completePop(result); _pages.removeLast(); - return pushNamed(routeName, arguments: arguments); + return await pushNamed(routeName, arguments: arguments); } @override @@ -150,11 +150,11 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future maybePop([T result]) => + Future maybePop([T? result]) => navigator.maybePop(result); @override - void pop([T result]) => navigator.pop(result); + void pop([T? result]) => navigator.pop(result); @override void popUntil(bool Function(Route) predicate) => @@ -163,19 +163,19 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, - {Object arguments}) { + {Object? arguments}) { popUntil(predicate); return pushNamed(newRouteName, arguments: arguments); } @override - String get modulePath => _router.modulePath; + String get modulePath => _router!.modulePath ?? '/'; @override - String get path => _router.path; + String get path => _router!.path ?? '/'; @override - Future push(Route route) { + Future push(Route route) { return navigator.push(route); } } diff --git a/flutter_modular/lib/src/inject/bind.dart b/flutter_modular/lib/src/inject/bind.dart index 988a4b2e..91ee65bf 100644 --- a/flutter_modular/lib/src/inject/bind.dart +++ b/flutter_modular/lib/src/inject/bind.dart @@ -47,3 +47,7 @@ class BindInject extends Bind { BindInject(this.inject, {this.singleton = true, this.lazy = true}) : super(inject, singleton: singleton, lazy: lazy); } + +class BindEmpty extends Bind { + BindEmpty() : super((e) => Object()); +} diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/lib/src/inject/inject.dart index ae9594ad..08891cff 100644 --- a/flutter_modular/lib/src/inject/inject.dart +++ b/flutter_modular/lib/src/inject/inject.dart @@ -7,17 +7,16 @@ class Inject { ///Bind has access to the arguments coming from the routes. ///If you need specific access, do it through functions. @deprecated - Map params = {}; + Map? params = {}; final List typesInRequest; - Inject({this.params, this.typesInRequest}); + Inject({this.params, this.typesInRequest = const []}); - B call({Map params, B defaultValue}) => + B? call({Map params = const {}, B? defaultValue}) => get(params: params, defaultValue: defaultValue); /// get injected dependency - B get({Map params, B defaultValue}) { - params ??= {}; + B? get({Map params = const {}, B? defaultValue}) { return Modular.get( params: params, typesInRequest: typesInRequest, @@ -33,5 +32,5 @@ class Inject { mixin InjectMixinBase { final Inject _inject = Inject(); - S get() => _inject.get(); + S? get() => _inject.get(); } diff --git a/flutter_modular/lib/src/interfaces/child_module.dart b/flutter_modular/lib/src/interfaces/child_module.dart index a89c96ae..3f2705e3 100644 --- a/flutter_modular/lib/src/interfaces/child_module.dart +++ b/flutter_modular/lib/src/interfaces/child_module.dart @@ -4,7 +4,7 @@ import '../../flutter_modular.dart'; import '../routers/modular_router.dart'; abstract class ChildModule { - List _binds; + late List _binds; List get binds; List get routers; @@ -20,7 +20,8 @@ abstract class ChildModule { final Map _singletonBinds = {}; - T getBind(Map params, {List typesInRequest}) { + T? getBind(Map params, + {required List typesInRequest}) { T bindValue; var type = _getInjectType(); if (_singletonBinds.containsKey(type)) { @@ -29,8 +30,8 @@ abstract class ChildModule { } var bind = _binds.firstWhere((b) => b.inject is T Function(Inject), - orElse: () => null); - if (bind == null) { + orElse: () => BindEmpty()); + if (bind is BindEmpty) { typesInRequest.remove(type); return null; } @@ -91,13 +92,14 @@ ${typesInRequest.join('\n')} } Type _getInjectType() { + var foundType = B; _singletonBinds.forEach((key, value) { if (value is B) { - return key; + foundType = key; } }); - return B; + return foundType; } /// Create a instance of all binds isn't lazy Loaded diff --git a/flutter_modular/lib/src/interfaces/modular_interface.dart b/flutter_modular/lib/src/interfaces/modular_interface.dart index c8106296..11e37f41 100644 --- a/flutter_modular/lib/src/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_interface.dart @@ -11,10 +11,10 @@ abstract class ModularInterface { IModularNavigator get to; IModularNavigator get link; - B get({ - Map params, - List typesInRequest, - B defaultValue, + B? get({ + Map params = const {}, + List typesInRequest = const [], + B? defaultValue, }); - void dispose([String moduleName]); + void dispose(); } diff --git a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart index 7396f313..47a50d3f 100644 --- a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart @@ -9,7 +9,7 @@ abstract class IModularNavigator { /// ``` /// Modular.to.push(MaterialPageRoute(builder: (context) => HomePage()),); /// ``` - Future push(Route route); + Future push(Route route); /// Pop the current route off the navigator and navigate to a route. /// @@ -20,7 +20,7 @@ abstract class IModularNavigator { /// ``` /// Modular.to.popAndPushNamed('/home', arguments: 10); /// ``` - Future popAndPushNamed( + Future popAndPushNamed( String routeName, {TO result, Object arguments}); @@ -34,7 +34,7 @@ abstract class IModularNavigator { /// ``` /// Modular.to.pushNamed('/home', arguments: 10); /// ``` - Future pushNamed(String routeName, {Object arguments}); + Future pushNamed(String routeName, {Object arguments}); /// Push the route with the given name onto the navigator that most tightly /// encloses the given context, and then remove all the previous routes until @@ -47,7 +47,7 @@ abstract class IModularNavigator { /// ``` /// Modular.to.pushNamedAndRemoveUntil('/home', ModalRoute.withName('/'), arguments: 10); /// ``` - Future pushNamedAndRemoveUntil( + Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, {Object arguments}); @@ -62,7 +62,7 @@ abstract class IModularNavigator { /// ``` /// Modular.to.pushReplacementNamed('/home', arguments: 10); /// ``` - Future pushReplacementNamed( + Future pushReplacementNamed( String routeName, {TO result, Object arguments}); diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/lib/src/modular_base.dart index bca9818d..24a713cf 100644 --- a/flutter_modular/lib/src/modular_base.dart +++ b/flutter_modular/lib/src/modular_base.dart @@ -28,7 +28,7 @@ extension ModularExtension on MaterialApp { MaterialApp modular() { final app = MaterialApp.router( key: key, - //scaffoldMessengerKey: scaffoldMessengerKey, + // scaffoldMessengerKey: scaffoldMessengerKey, routeInformationProvider: routeInformationProvider, backButtonDispatcher: backButtonDispatcher, builder: builder, @@ -53,7 +53,7 @@ extension ModularExtension on MaterialApp { debugShowCheckedModeBanner: debugShowCheckedModeBanner, shortcuts: shortcuts, actions: actions, - //restorationScopeId: restorationScopeId, + // restorationScopeId: restorationScopeId, routeInformationParser: _routeInformationParser, routerDelegate: _routerDelegate, ); diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/lib/src/modular_impl.dart index 48f6282b..da3ebf95 100644 --- a/flutter_modular/lib/src/modular_impl.dart +++ b/flutter_modular/lib/src/modular_impl.dart @@ -4,16 +4,16 @@ import '../flutter_modular.dart'; import 'delegates/modular_router_delegate.dart'; import 'interfaces/modular_interface.dart'; -ChildModule _initialModule; +late ChildModule _initialModule; class ModularImpl implements ModularInterface { final ModularRouterDelegate routerDelegate; final Map injectMap; - IModularNavigator navigatorDelegate; + IModularNavigator? navigatorDelegate; ModularImpl({ - this.routerDelegate, - this.injectMap, + required this.routerDelegate, + required this.injectMap, this.navigatorDelegate, }); @@ -28,8 +28,7 @@ class ModularImpl implements ModularInterface { } @override - void bindModule(ChildModule module, [String path]) { - assert(module != null); + void bindModule(ChildModule module, [String path = '']) { final name = module.runtimeType.toString(); if (!injectMap.containsKey(name)) { module.paths.add(path); @@ -37,7 +36,7 @@ class ModularImpl implements ModularInterface { module.instance(); debugPrintModular("-- ${module.runtimeType.toString()} INITIALIZED"); } else { - injectMap[name].paths.add(path); + injectMap[name]?.paths.add(path); } } @@ -61,21 +60,19 @@ class ModularImpl implements ModularInterface { @override B get( - {Map params, - List typesInRequest, - B defaultValue}) { + {Map params = const {}, + List typesInRequest = const [], + B? defaultValue}) { if (B.toString() == 'dynamic') { throw ModularError('not allow for dynamic values'); } - - typesInRequest ??= []; - - B result; + B? result; if (typesInRequest.isEmpty) { final module = routerDelegate - .currentConfiguration.currentModule.runtimeType - .toString(); + .currentConfiguration?.currentModule.runtimeType + .toString() ?? + '=global'; result = _getInjectableObject(module, params: params, typesInRequest: typesInRequest); } @@ -99,24 +96,26 @@ class ModularImpl implements ModularInterface { throw ModularError('${B.toString()} not found'); } - B _getInjectableObject( + B? _getInjectableObject( String tag, { - Map params, - List typesInRequest, + Map params = const {}, + List typesInRequest = const [], bool checkKey = true, }) { - B value; + B? value; if (!checkKey) { - value = injectMap[tag].getBind(params, typesInRequest: typesInRequest); + value = + injectMap[tag]?.getBind(params, typesInRequest: typesInRequest); } else if (injectMap.containsKey(tag)) { - value = injectMap[tag].getBind(params, typesInRequest: typesInRequest); + value = + injectMap[tag]?.getBind(params, typesInRequest: typesInRequest); } return value; } @override - void dispose([String moduleName]) { + void dispose() { if (B.toString() == 'dynamic') { throw ModularError('not allow for dynamic values'); } @@ -129,6 +128,6 @@ class ModularImpl implements ModularInterface { } bool _removeInjectableObject(String tag) { - return injectMap[tag].remove(); + return injectMap[tag]?.remove() ?? false; } } diff --git a/flutter_modular/lib/src/routers/modular_link.dart b/flutter_modular/lib/src/routers/modular_link.dart index 913fe4f5..19db2343 100644 --- a/flutter_modular/lib/src/routers/modular_link.dart +++ b/flutter_modular/lib/src/routers/modular_link.dart @@ -13,23 +13,23 @@ class ModularLink implements IModularNavigator { bool canPop() => delegate.canPop(); @override - Future push(Route route) => delegate.push(route); + Future push(Route route) => delegate.push(route); @override - Future maybePop([T result]) => + Future maybePop([T? result]) => delegate.maybePop(result); @override - void pop([T result]) => delegate.pop(result); + void pop([T? result]) => delegate.pop(result); @override void popUntil(bool Function(Route) predicate) => delegate.popUntil(predicate); @override - String get modulePath => delegate.lastPage.modulePath; + String get modulePath => delegate.lastPage.modulePath ?? '/'; @override - String get path => delegate.lastPage.path; + String get path => delegate.lastPage.path ?? '/'; @override void navigate(String path, {arguments}) => delegate.navigate( @@ -40,8 +40,8 @@ class ModularLink implements IModularNavigator { @override Future popAndPushNamed( String routeName, - {TO result, - Object arguments}) { + {TO? result, + Object? arguments}) { return delegate.popAndPushNamed( modulePath + routeName, result: result, @@ -50,7 +50,7 @@ class ModularLink implements IModularNavigator { } @override - Future pushNamed(String routeName, {Object arguments}) { + Future pushNamed(String routeName, {Object? arguments}) { return delegate.pushNamed( modulePath + routeName, arguments: arguments, @@ -60,7 +60,7 @@ class ModularLink implements IModularNavigator { @override Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, - {Object arguments}) { + {Object? arguments}) { return delegate.pushNamedAndRemoveUntil( modulePath + newRouteName, predicate, @@ -71,8 +71,8 @@ class ModularLink implements IModularNavigator { @override Future pushReplacementNamed( String routeName, - {TO result, - Object arguments}) { + {TO? result, + Object? arguments}) { return delegate.pushReplacementNamed( modulePath + routeName, result: result, diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/lib/src/routers/modular_page.dart index 2207da93..62b26b83 100644 --- a/flutter_modular/lib/src/routers/modular_page.dart +++ b/flutter_modular/lib/src/routers/modular_page.dart @@ -9,29 +9,29 @@ final Map _allCompleters = {}; class ModularPage extends Page { final ModularRouter router; - ModularPage({Key key, this.router}) - : super(key: key, name: router.path, arguments: router.args.data); + ModularPage({LocalKey? key, required this.router}) + : super(key: key, name: router.path, arguments: router.args?.data); Future waitPop() { if (_allCompleters.containsKey(hashCode)) { - return _allCompleters[hashCode].future; + return (_allCompleters[hashCode] as Completer).future; } else { _allCompleters[hashCode] = Completer(); - return _allCompleters[hashCode].future; + return (_allCompleters[hashCode] as Completer).future; } } void completePop(T result) { if (_allCompleters.containsKey(hashCode) && - !_allCompleters[hashCode].isCompleted) { - _allCompleters[hashCode].complete(result); + !(_allCompleters[hashCode] as Completer).isCompleted) { + (_allCompleters[hashCode] as Completer).complete(result); _allCompleters.remove(hashCode); } } @override Route createRoute(BuildContext context) { - return router.getPageRoute(this); + return router.getPageRoute(this); } // @override diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index 714588de..018690d6 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -13,14 +13,16 @@ import '../utils/modular_arguments.dart'; typedef RouteBuilder = MaterialPageRoute Function( WidgetBuilder, RouteSettings); typedef ModularChild = Widget Function( - BuildContext context, ModularArguments args); + BuildContext context, ModularArguments? args); class ModularRouter { - final ChildModule currentModule; + final ChildModule? currentModule; - final ModularArguments args; + final ModularArguments? args; - final String path; + final List children; + + final String? path; /// /// Paramenter name: [routerName] @@ -43,7 +45,7 @@ class ModularRouter { /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final ModularChild child; + final ModularChild? child; /// /// Paramenter name: [module] @@ -54,7 +56,7 @@ class ModularRouter { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final ChildModule module; + final ChildModule? module; /// /// Paramenter name: [params] @@ -65,7 +67,7 @@ class ModularRouter { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final Map params; + final Map? params; /// /// Paramenter name: [guards] @@ -96,7 +98,7 @@ class ModularRouter { /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final List guards; + final List? guards; /// /// Paramenter name: [transition] @@ -156,7 +158,7 @@ class ModularRouter { /// ``` /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final CustomTransition customTransition; + final CustomTransition? customTransition; /// /// Paramenter name: [transition] @@ -165,14 +167,14 @@ class ModularRouter { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final RouteBuilder routeGenerator; - final String modulePath; + final RouteBuilder? routeGenerator; + final String? modulePath; final Duration duration; final Map< TransitionType, PageRouteBuilder Function( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings, )> transitions = { @@ -192,6 +194,7 @@ class ModularRouter { ModularRouter( this.routerName, { this.path = '/', + this.children = const [], this.args = const ModularArguments(), this.module, this.child, @@ -203,33 +206,35 @@ class ModularRouter { this.customTransition, this.duration = const Duration(milliseconds: 300), this.modulePath = '/', - }) : assert(routerName != null), - assert(transition != null), - assert((transition == TransitionType.custom && + }) : assert((transition == TransitionType.custom && customTransition != null) || transition != TransitionType.custom && customTransition == null), assert((module == null && child != null) || - (module != null && child == null)); + (module != null && child == null)), + assert(module == null ? true : children.isEmpty, + 'Módulo não pode conter rotas aninhadas (children)'); ModularRouter copyWith( - {ModularChild child, - String routerName, - ChildModule module, - ChildModule currentModule, - Map params, - List guards, - TransitionType transition, - RouteBuilder routeGenerator, - String modulePath, - String path, - String duration, - Completer popRoute, - ModularArguments args, - CustomTransition customTransition}) { + {ModularChild? child, + String? routerName, + ChildModule? module, + List? children, + ChildModule? currentModule, + Map? params, + List? guards, + TransitionType? transition, + RouteBuilder? routeGenerator, + String? modulePath, + String? path, + Duration? duration, + Completer? popRoute, + ModularArguments? args, + CustomTransition? customTransition}) { return ModularRouter( routerName ?? this.routerName, child: child ?? this.child, args: args ?? this.args, + children: children ?? this.children, module: module ?? this.module, currentModule: currentModule ?? this.currentModule, params: params ?? this.params, @@ -244,10 +249,10 @@ class ModularRouter { } static List group({ - @required List routes, - List guards, - TransitionType transition, - CustomTransition customTransition, + required List routes, + List? guards, + TransitionType? transition, + CustomTransition? customTransition, }) { return routes.map((r) { return r.copyWith( @@ -258,25 +263,29 @@ class ModularRouter { }).toList(); } - Route getPageRoute(RouteSettings settings) { + Route getPageRoute(RouteSettings settings) { if (transition == TransitionType.custom && customTransition != null) { return PageRouteBuilder( pageBuilder: (context, _, __) { - return child(context, args); + if (child != null) { + return child!(context, args); + } else { + throw ModularError('Child not be null'); + } }, settings: settings, - transitionsBuilder: customTransition.transitionBuilder, - transitionDuration: customTransition.transitionDuration, + transitionsBuilder: customTransition!.transitionBuilder, + transitionDuration: customTransition!.transitionDuration, ); } else if (transition == TransitionType.defaultTransition) { // Helper function Widget widgetBuilder(BuildContext context) { //return disposablePage; - return child(context, args); + return child!(context, args); } if (routeGenerator != null) { - return routeGenerator(widgetBuilder, settings); + return routeGenerator!(widgetBuilder, settings) as Route; } return MaterialPageRoute( settings: settings, @@ -284,7 +293,11 @@ class ModularRouter { ); } else { var selectTransition = transitions[transition]; - return selectTransition(child, args, duration, settings); + if (selectTransition != null) { + return selectTransition(child!, args, duration, settings) as Route; + } else { + throw ModularError('Page Not Found'); + } } } @@ -329,6 +342,6 @@ class CustomTransition { final Duration transitionDuration; CustomTransition( - {@required this.transitionBuilder, + {required this.transitionBuilder, this.transitionDuration = const Duration(milliseconds: 300)}); } diff --git a/flutter_modular/lib/src/test/modular_test_interface.dart b/flutter_modular/lib/src/test/modular_test_interface.dart index c4045702..7ce7ce46 100644 --- a/flutter_modular/lib/src/test/modular_test_interface.dart +++ b/flutter_modular/lib/src/test/modular_test_interface.dart @@ -13,8 +13,8 @@ abstract class IModularTest { IModularTest get modulardependency; void load({ - IModularTest changedependency, - List changeBinds, + IModularTest? changedependency, + List? changeBinds, bool isLoadDependency = true, }) { final dependency = getDendencies( @@ -34,8 +34,8 @@ abstract class IModularTest { @visibleForTesting IModularTest getDendencies({ - IModularTest changedependency, - @required bool isLoadDependency, + IModularTest? changedependency, + required bool isLoadDependency, }) { changedependency ??= modulardependency; @@ -46,27 +46,27 @@ abstract class IModularTest { return changedependency; } - bool _isDependencyRequired(IModularTest dependency, bool isLoadDependency) => + bool _isDependencyRequired(IModularTest? dependency, bool isLoadDependency) => dependency == null && isLoadDependency && isMainModule; @visibleForTesting - List getBinds(List changeBinds) { + List getBinds(List? changeBinds) { final mergedChangeBinds = mergeBinds(changeBinds, binds); return mergedChangeBinds; } @visibleForTesting - List mergeBinds(List changeBinds, List defaultBinds) { + List mergeBinds(List? changeBinds, List? defaultBinds) { final resultBinds = defaultBinds ?? []; for (var bind in (changeBinds ?? [])) { var changedBind = resultBinds.firstWhere( (item) => item.runtimeType == bind.runtimeType, - orElse: () => null, + orElse: () => BindEmpty(), ); - if (changedBind != null) resultBinds.remove(changedBind); + if (changedBind is! BindEmpty) resultBinds.remove(changedBind); resultBinds.add(bind); } @@ -82,9 +82,9 @@ abstract class IModularTest { @visibleForTesting void loadModularDependency({ - @required bool isLoadDependency, - @required List changeBinds, - @required IModularTest dependency, + required bool isLoadDependency, + required List? changeBinds, + required IModularTest? dependency, }) { if (isLoadDependency && dependency != null) { dependency.load(changeBinds: changeBinds); diff --git a/flutter_modular/lib/src/test/utils_test.dart b/flutter_modular/lib/src/test/utils_test.dart index bcebf59d..981eee22 100644 --- a/flutter_modular/lib/src/test/utils_test.dart +++ b/flutter_modular/lib/src/test/utils_test.dart @@ -3,28 +3,29 @@ import 'package:flutter/material.dart'; import '../../flutter_modular.dart'; void initModule(ChildModule module, - {List changeBinds, bool initialModule}) { + {List changeBinds = const [], bool initialModule = false}) { //Modular.debugMode = false; final list = module.binds; final changedList = List.from(list); - for (var item in list ?? []) { - var dep = (changeBinds ?? []).firstWhere((dep) { + for (var item in list) { + var dep = (changeBinds).firstWhere((dep) { return item.runtimeType == dep.runtimeType; - }, orElse: () => null); - if (dep != null) { + }, orElse: () => BindEmpty()); + if (dep is BindEmpty) { changedList.remove(item); changedList.add(dep); } } module.changeBinds(changedList); - if (initialModule ?? false) { + if (initialModule) { // Modular.init(module); } else { // Modular.bindModule(module); } } -void initModules(List modules, {List changeBinds}) { +void initModules(List modules, + {List changeBinds = const []}) { for (var module in modules) { initModule(module, changeBinds: changeBinds); } diff --git a/flutter_modular/lib/src/transitions/page_transition.dart b/flutter_modular/lib/src/transitions/page_transition.dart index 33366bd9..a25f5df8 100644 --- a/flutter_modular/lib/src/transitions/page_transition.dart +++ b/flutter_modular/lib/src/transitions/page_transition.dart @@ -21,13 +21,13 @@ class PageTransition extends PageRouteBuilder { final Duration duration; PageTransition({ - Key key, - @required this.builder, - @required this.type, + Key? key, + required this.builder, + required this.type, this.curve = Curves.easeInOut, - this.alignment, + this.alignment = Alignment.center, this.duration = const Duration(milliseconds: 600), - RouteSettings settings, + RouteSettings? settings, }) : super( pageBuilder: (context, animation, secondaryAnimation) { return builder(context); diff --git a/flutter_modular/lib/src/transitions/transitions.dart b/flutter_modular/lib/src/transitions/transitions.dart index 8ddff6f9..ad340684 100644 --- a/flutter_modular/lib/src/transitions/transitions.dart +++ b/flutter_modular/lib/src/transitions/transitions.dart @@ -6,10 +6,10 @@ import 'page_transition.dart'; PageRouteBuilder fadeInTransition( Widget Function( BuildContext, - ModularArguments, + ModularArguments?, ) builder, - ModularArguments args, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageRouteBuilder( @@ -27,8 +27,8 @@ PageRouteBuilder fadeInTransition( } PageRouteBuilder noTransition( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageRouteBuilder( @@ -40,8 +40,8 @@ PageRouteBuilder noTransition( } PageRouteBuilder rightToLeft( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -55,8 +55,8 @@ PageRouteBuilder rightToLeft( } PageRouteBuilder leftToRight( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -70,8 +70,8 @@ PageRouteBuilder leftToRight( } PageRouteBuilder upToDown( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -85,8 +85,8 @@ PageRouteBuilder upToDown( } PageRouteBuilder downToUp( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -100,8 +100,8 @@ PageRouteBuilder downToUp( } PageRouteBuilder scale( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -115,8 +115,8 @@ PageRouteBuilder scale( } PageRouteBuilder rotate( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -130,8 +130,8 @@ PageRouteBuilder rotate( } PageRouteBuilder size( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -145,8 +145,8 @@ PageRouteBuilder size( } PageRouteBuilder rightToLeftWithFade( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( @@ -160,8 +160,8 @@ PageRouteBuilder rightToLeftWithFade( } PageRouteBuilder leftToRightWithFade( - Widget Function(BuildContext, ModularArguments) builder, - ModularArguments args, + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, Duration transitionDuration, RouteSettings settings) { return PageTransition( diff --git a/flutter_modular/lib/src/utils/modular_arguments.dart b/flutter_modular/lib/src/utils/modular_arguments.dart index 6307fad5..169a52a2 100644 --- a/flutter_modular/lib/src/utils/modular_arguments.dart +++ b/flutter_modular/lib/src/utils/modular_arguments.dart @@ -1,11 +1,17 @@ +import 'package:flutter/foundation.dart'; + class ModularArguments { - final Map params; - final dynamic data; + final Map? params; + final dynamic? data; const ModularArguments({this.params, this.data}); - ModularArguments copyWith({Map params, dynamic data}) { + ModularArguments copyWith({Map? params, dynamic? data}) { return ModularArguments( params: params ?? this.params, data: data ?? this.data); } + + factory ModularArguments.empty() { + return ModularArguments(); + } } diff --git a/flutter_modular/lib/src/utils/no_animation_transition_delegate.dart b/flutter_modular/lib/src/utils/no_animation_transition_delegate.dart deleted file mode 100644 index 9c0d7adb..00000000 --- a/flutter_modular/lib/src/utils/no_animation_transition_delegate.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/material.dart'; - -class NoAnimationTransitionDelegate extends TransitionDelegate { - @override - Iterable resolve({ - List newPageRouteHistory, - Map - locationToExitingPageRoute, - Map> - pageRouteToPagelessRoutes, - }) { - final results = []; - - for (final pageRoute in newPageRouteHistory) { - if (pageRoute.isWaitingForEnteringDecision) { - pageRoute.markForAdd(); - } - results.add(pageRoute); - } - - for (final exitingPageRoute in locationToExitingPageRoute.values) { - if (exitingPageRoute.isWaitingForExitingDecision) { - exitingPageRoute.markForRemove(); - final pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute]; - if (pagelessRoutes != null) { - for (final pagelessRoute in pagelessRoutes) { - pagelessRoute.markForRemove(); - } - } - } - - results.add(exitingPageRoute); - } - return results; - } -} diff --git a/flutter_modular/lib/src/widgets/modular_app.dart b/flutter_modular/lib/src/widgets/modular_app.dart index 32194af0..f0354faa 100644 --- a/flutter_modular/lib/src/widgets/modular_app.dart +++ b/flutter_modular/lib/src/widgets/modular_app.dart @@ -6,8 +6,8 @@ class ModularApp extends StatefulWidget { final MainModule module; ModularApp({ - Key key, - this.module, + Key? key, + required this.module, }) : super(key: key); @override diff --git a/flutter_modular/lib/src/widgets/modular_state.dart b/flutter_modular/lib/src/widgets/modular_state.dart index 064a5009..8fc7dffe 100644 --- a/flutter_modular/lib/src/widgets/modular_state.dart +++ b/flutter_modular/lib/src/widgets/modular_state.dart @@ -4,7 +4,7 @@ import '../../flutter_modular.dart'; abstract class ModularState extends State { - final TBind controller = Modular.get(); + final TBind? controller = Modular.get(); @override void dispose() { diff --git a/flutter_modular/lib/src/widgets/router_outlet.dart b/flutter_modular/lib/src/widgets/router_outlet.dart index 85fcffc6..c4f36f57 100644 --- a/flutter_modular/lib/src/widgets/router_outlet.dart +++ b/flutter_modular/lib/src/widgets/router_outlet.dart @@ -3,59 +3,69 @@ import 'package:flutter/widgets.dart'; import '../../flutter_modular.dart'; import 'widget_module.dart'; -class RouterOutlet extends StatefulWidget { - final ChildModule module; - final String initialRoute; - final Key navigatorKey; - final bool keepAlive; - final void Function(String route) onChangeRoute; - - RouterOutlet({ - Key key, - @required this.module, - this.navigatorKey, - this.initialRoute = '/', - this.keepAlive = true, - this.onChangeRoute, - }) : super(key: key) { - module.paths.add(runtimeType.toString()); - } - +class RouterOutlet extends StatelessWidget { @override - _RouterOutletState createState() => _RouterOutletState(); + Widget build(BuildContext context) { + return Container(); + // return Router( + // routerDelegate: null, + // ); + } } -class _RouterOutletState extends State - with AutomaticKeepAliveClientMixin { - GlobalKey _key; - @override - void initState() { - super.initState(); - // _key = widget.navigatorKey ?? - // Modular.outletNavigatorKey(widget.module.runtimeType.toString()); - } +// class RouterOutlet extends StatefulWidget { +// final ChildModule module; +// final String initialRoute; +// final Key navigatorKey; +// final bool keepAlive; +// final void Function(String route) onChangeRoute; - @override - Widget build(BuildContext context) { - super.build(context); - return WillPopScope( - onWillPop: () async { - return !await _key.currentState.maybePop(); - }, - child: ModularProvider( - module: widget.module, - child: Navigator( - key: _key, - initialRoute: widget.initialRoute, - // onGenerateRoute: (setting) { - // return Modular.generateRoute( - // setting, widget.module, widget.onChangeRoute); - // }, - ), - ), - ); - } +// RouterOutlet({ +// Key key, +// @required this.module, +// this.navigatorKey, +// this.initialRoute = '/', +// this.keepAlive = true, +// this.onChangeRoute, +// }) : super(key: key) { +// module.paths.add(runtimeType.toString()); +// } - @override - bool get wantKeepAlive => widget.keepAlive; -} +// @override +// _RouterOutletState createState() => _RouterOutletState(); +// } + +// class _RouterOutletState extends State +// with AutomaticKeepAliveClientMixin { +// GlobalKey _key; +// @override +// void initState() { +// super.initState(); +// // _key = widget.navigatorKey ?? +// // Modular.outletNavigatorKey(widget.module.runtimeType.toString()); +// } + +// @override +// Widget build(BuildContext context) { +// super.build(context); +// return WillPopScope( +// onWillPop: () async { +// return !await _key.currentState.maybePop(); +// }, +// child: ModularProvider( +// module: widget.module, +// child: Navigator( +// key: _key, +// initialRoute: widget.initialRoute, +// // onGenerateRoute: (setting) { +// // return Modular.generateRoute( +// // setting, widget.module, widget.onChangeRoute); +// // }, +// ), +// ), +// ); +// } + +// @override +// bool get wantKeepAlive => widget.keepAlive; +// } diff --git a/flutter_modular/lib/src/widgets/widget_module.dart b/flutter_modular/lib/src/widgets/widget_module.dart index 47b4338d..5a8f0b11 100644 --- a/flutter_modular/lib/src/widgets/widget_module.dart +++ b/flutter_modular/lib/src/widgets/widget_module.dart @@ -30,7 +30,8 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { } @override - T getBind(Map params, {List typesInRequest}) { + T? getBind(Map params, + {List typesInRequest = const []}) { return _fakeModule.getBind(params, typesInRequest: typesInRequest); } @@ -48,7 +49,7 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { } @override - List get routers => null; + List get routers => const []; @override Widget build(BuildContext context) { @@ -60,24 +61,25 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { } class _FakeModule extends ChildModule { - final List bindsInject; + final List? bindsInject; _FakeModule({this.bindsInject}) { paths.add(runtimeType.toString()); } @override - List get binds => bindsInject; + List get binds => bindsInject ?? []; @override - List get routers => null; + List get routers => []; } class ModularProvider extends StatefulWidget { final ChildModule module; final Widget child; - const ModularProvider({Key key, this.module, this.child}) : super(key: key); + const ModularProvider({Key? key, required this.module, required this.child}) + : super(key: key); @override _ModularProviderState createState() => _ModularProviderState(); diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 856b9bc1..d71303ce 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -4,7 +4,7 @@ version: 2.5.0-alpha.3 homepage: https://github.com/Flutterando/modular environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-29.10.beta <3.0.0" dependencies: flutter: diff --git a/modular.code-workspace b/modular.code-workspace index 0e66ce0b..09567775 100644 --- a/modular.code-workspace +++ b/modular.code-workspace @@ -8,6 +8,6 @@ } ], "settings": { - "dart.flutterSdkPath": "/Users/jacobmoura/fvm/versions/stable" + "dart.flutterSdkPath": "/Users/jacobmoura/fvm/versions/beta" } } \ No newline at end of file From 1f0a1b4727b3630b49d51d77bb4eeb94b151db8d Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 1 Dec 2020 11:16:05 -0300 Subject: [PATCH 29/71] nullsafety --- .../modular_route_information_parser.dart | 30 ++++++++++++------- .../lib/src/routers/modular_link.dart | 2 -- .../lib/src/routers/modular_router.dart | 1 - flutter_modular/pubspec.yaml | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart index 088e1c86..42953ed1 100644 --- a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/delegates/modular_route_information_parser.dart @@ -25,10 +25,10 @@ class ModularRouteInformationParser routers.sort((preview, actual) { return preview.routerName.contains('/:') ? 1 : 0; }); - for (ModularRouter? route in routers) { - route = _searchRoute(route, routerName, path); - if (route != null) { - return route; + for (var route in routers) { + var r = _searchRoute(route, routerName, path); + if (r != null) { + return r; } } return null; @@ -77,8 +77,16 @@ class ModularRouteInformationParser return router; } } else { + if (tempRouteName.split('/').length != path.split('/').length) { + return null; + } var parseRoute = _parseUrlParams(route, tempRouteName, path); - if (parseRoute != null && parseRoute.currentModule != null) { + + if (path != parseRoute.path) { + return null; + } + + if (parseRoute.currentModule != null) { Modular.bindModule(parseRoute.currentModule!, path); return route.copyWith(path: path); } @@ -97,12 +105,8 @@ class ModularRouteInformationParser return newUrl.join("/"); } - ModularRouter? _parseUrlParams( + ModularRouter _parseUrlParams( ModularRouter router, String routeNamed, String path) { - if (routeNamed.split('/').length != path.split('/').length) { - return null; - } - if (routeNamed.contains('/:')) { final regExp = RegExp( "^${prepareToRegex(routeNamed)}\$", @@ -114,6 +118,7 @@ class ModularRouteInformationParser var paramPos = 0; final routeParts = routeNamed.split('/'); final pathParts = path.split('/'); + var newPath = router.path!; // print('Match! Processing $path as $routeNamed'); @@ -121,6 +126,8 @@ class ModularRouteInformationParser if (routePart.contains(":")) { var paramName = routePart.replaceFirst(':', ''); if (pathParts[paramPos].isNotEmpty) { + newPath = + newPath.replaceFirst(':$paramName', pathParts[paramPos]); params[paramName] = pathParts[paramPos]; routeNamed = routeNamed.replaceFirst(routePart, params[paramName]!); @@ -130,7 +137,8 @@ class ModularRouteInformationParser } var _params = routeNamed != path ? null : params; - return router.copyWith(args: router.args!.copyWith(params: _params)); + return router.copyWith( + args: router.args!.copyWith(params: _params), path: newPath); } return router.copyWith(args: router.args!.copyWith(params: null)); diff --git a/flutter_modular/lib/src/routers/modular_link.dart b/flutter_modular/lib/src/routers/modular_link.dart index 19db2343..fcca63d5 100644 --- a/flutter_modular/lib/src/routers/modular_link.dart +++ b/flutter_modular/lib/src/routers/modular_link.dart @@ -1,7 +1,5 @@ import 'package:flutter/widgets.dart'; - import '../delegates/modular_router_delegate.dart'; - import '../interfaces/modular_navigator_interface.dart'; class ModularLink implements IModularNavigator { diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/lib/src/routers/modular_router.dart index 018690d6..28dcfe12 100644 --- a/flutter_modular/lib/src/routers/modular_router.dart +++ b/flutter_modular/lib/src/routers/modular_router.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import '../../flutter_modular.dart'; diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index d71303ce..0b38755e 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -4,7 +4,7 @@ version: 2.5.0-alpha.3 homepage: https://github.com/Flutterando/modular environment: - sdk: ">=2.12.0-29.10.beta <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" dependencies: flutter: From cc8771f6e8e1d4360fc035c0e5fcdcaf7acddb27 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 1 Dec 2020 17:19:59 -0300 Subject: [PATCH 30/71] Nullsafety --- .../.backup/abstract_router_test.dart | 46 --- flutter_modular/.backup/app/app_bloc.dart | 10 - flutter_modular/.backup/app/app_module.dart | 37 --- .../.backup/app/app_module_test_modular.dart | 26 -- flutter_modular/.backup/app/app_widget.dart | 11 - flutter_modular/.backup/app/guard/guard.dart | 11 - .../modules/forbidden/forbidden_widget.dart | 12 - .../.backup/app/modules/home/home_bloc.dart | 16 - .../.backup/app/modules/home/home_module.dart | 81 ----- .../home/home_module_test_modular.dart | 23 -- .../.backup/app/modules/home/home_widget.dart | 13 - .../app/modules/product/product_bloc.dart | 13 - .../app/modules/product/product_module.dart | 34 -- .../product/product_module_test_modular.dart | 25 -- .../app/modules/product/product_widget.dart | 13 - .../.backup/app/shared/app_info.state.dart | 9 - .../.backup/app/shared/ilocal_repository.dart | 5 - .../.backup/app/shared/local_mock.dart | 18 -- .../app/shared/local_storage_shared.dart | 18 -- flutter_modular/.backup/bind_test.dart | 19 -- flutter_modular/.backup/modular_app_test.dart | 13 - .../.backup/modular_extension_test.dart | 13 - flutter_modular/.backup/modular_impl.dart | 1 - .../.backup/modular_inject_test.dart | 58 ---- .../modular_module_test_interface_test.dart | 256 --------------- .../.backup/modular_stack_overflow_test.dart | 81 ----- flutter_modular/.backup/modular_test.dart | 126 -------- .../.backup/modular_test_test.dart | 69 ----- .../.backup/modular_widget_test.dart | 39 --- flutter_modular/.backup/new_route_test.dart | 22 -- .../.backup/routers/router_test.dart | 38 --- .../.backup/transition/transitions_test.dart | 53 ---- .../modular_route_information_parser.dart | 0 .../delegates/modular_router_delegate.dart | 0 .../exceptions/modular_error.dart | 0 .../{lib/src => .src}/inject/bind.dart | 0 .../{lib/src => .src}/inject/inject.dart | 0 .../src => .src}/interfaces/child_module.dart | 0 .../src => .src}/interfaces/disposable.dart | 0 .../src => .src}/interfaces/main_module.dart | 0 .../interfaces/modular_interface.dart | 0 .../modular_navigator_interface.dart | 0 .../src => .src}/interfaces/route_guard.dart | 0 .../{lib/src => .src}/modular_base.dart | 0 .../{lib/src => .src}/modular_impl.dart | 0 .../src => .src}/routers/modular_link.dart | 0 .../src => .src}/routers/modular_page.dart | 0 .../src => .src}/routers/modular_router.dart | 0 .../.src/test/modular_test_interface.dart | 95 ++++++ flutter_modular/.src/test/utils_test.dart | 44 +++ .../src => .src}/utils/modular_arguments.dart | 0 .../src => .src}/widgets/modular_app.dart | 0 .../src => .src}/widgets/modular_state.dart | 0 .../src => .src}/widgets/router_outlet.dart | 0 .../src => .src}/widgets/widget_module.dart | 0 flutter_modular/lib/flutter_modular.dart | 28 +- .../lib/src/core/errors/errors.dart | 13 + flutter_modular/lib/src/core/inject/bind.dart | 58 ++++ .../lib/src/core/inject/inject.dart | 10 + .../lib/src/core/interfaces/disposable.dart | 7 + .../lib/src/core/interfaces/route_guard.dart | 7 + .../src/core/models/modular_arguments.dart | 17 + .../lib/src/core/models/modular_router.dart | 292 ++++++++++++++++++ .../lib/src/core/modules/child_module.dart | 116 +++++++ .../lib/src/core/modules/main_module.dart | 7 + .../transitions/page_transition.dart | 11 +- .../{ => core}/transitions/transitions.dart | 2 +- .../interfaces/modular_interface.dart | 21 ++ .../modular_navigator_interface.dart | 104 +++++++ .../lib/src/presenters/modular_base.dart | 62 ++++ .../lib/src/presenters/modular_impl.dart | 136 ++++++++ .../presenters/navigation/modular_page.dart | 78 +++++ .../modular_route_information_parser.dart | 179 +++++++++++ .../navigation/modular_router_delegate.dart | 184 +++++++++++ .../src/presenters/widgets/modular_app.dart | 38 +++ .../src/presenters/widgets/modular_state.dart | 14 + .../src/presenters/widgets/router_outlet.dart | 70 +++++ .../src/presenters/widgets/widget_module.dart | 109 +++++++ .../lib/src/test/modular_test_interface.dart | 7 +- flutter_modular/lib/src/test/utils_test.dart | 4 +- .../test/src/core/errors/errors_test.dart | 8 + .../test/src/core/inject/bind_test.dart | 17 + .../core/models/modular_arguments_test.dart | 10 + .../src/core/models/modular_router_test.dart | 46 +++ .../src/core/modules/child_module_test.dart | 116 +++++++ .../modular_route_information_parse_test.dart | 133 ++++++++ 86 files changed, 2013 insertions(+), 1239 deletions(-) delete mode 100644 flutter_modular/.backup/abstract_router_test.dart delete mode 100644 flutter_modular/.backup/app/app_bloc.dart delete mode 100644 flutter_modular/.backup/app/app_module.dart delete mode 100644 flutter_modular/.backup/app/app_module_test_modular.dart delete mode 100644 flutter_modular/.backup/app/app_widget.dart delete mode 100644 flutter_modular/.backup/app/guard/guard.dart delete mode 100644 flutter_modular/.backup/app/modules/forbidden/forbidden_widget.dart delete mode 100644 flutter_modular/.backup/app/modules/home/home_bloc.dart delete mode 100644 flutter_modular/.backup/app/modules/home/home_module.dart delete mode 100644 flutter_modular/.backup/app/modules/home/home_module_test_modular.dart delete mode 100644 flutter_modular/.backup/app/modules/home/home_widget.dart delete mode 100644 flutter_modular/.backup/app/modules/product/product_bloc.dart delete mode 100644 flutter_modular/.backup/app/modules/product/product_module.dart delete mode 100644 flutter_modular/.backup/app/modules/product/product_module_test_modular.dart delete mode 100644 flutter_modular/.backup/app/modules/product/product_widget.dart delete mode 100644 flutter_modular/.backup/app/shared/app_info.state.dart delete mode 100644 flutter_modular/.backup/app/shared/ilocal_repository.dart delete mode 100644 flutter_modular/.backup/app/shared/local_mock.dart delete mode 100644 flutter_modular/.backup/app/shared/local_storage_shared.dart delete mode 100644 flutter_modular/.backup/bind_test.dart delete mode 100644 flutter_modular/.backup/modular_app_test.dart delete mode 100644 flutter_modular/.backup/modular_extension_test.dart delete mode 100644 flutter_modular/.backup/modular_impl.dart delete mode 100644 flutter_modular/.backup/modular_inject_test.dart delete mode 100644 flutter_modular/.backup/modular_module_test_interface_test.dart delete mode 100644 flutter_modular/.backup/modular_stack_overflow_test.dart delete mode 100644 flutter_modular/.backup/modular_test.dart delete mode 100644 flutter_modular/.backup/modular_test_test.dart delete mode 100644 flutter_modular/.backup/modular_widget_test.dart delete mode 100644 flutter_modular/.backup/new_route_test.dart delete mode 100644 flutter_modular/.backup/routers/router_test.dart delete mode 100644 flutter_modular/.backup/transition/transitions_test.dart rename flutter_modular/{lib/src => .src}/delegates/modular_route_information_parser.dart (100%) rename flutter_modular/{lib/src => .src}/delegates/modular_router_delegate.dart (100%) rename flutter_modular/{lib/src => .src}/exceptions/modular_error.dart (100%) rename flutter_modular/{lib/src => .src}/inject/bind.dart (100%) rename flutter_modular/{lib/src => .src}/inject/inject.dart (100%) rename flutter_modular/{lib/src => .src}/interfaces/child_module.dart (100%) rename flutter_modular/{lib/src => .src}/interfaces/disposable.dart (100%) rename flutter_modular/{lib/src => .src}/interfaces/main_module.dart (100%) rename flutter_modular/{lib/src => .src}/interfaces/modular_interface.dart (100%) rename flutter_modular/{lib/src => .src}/interfaces/modular_navigator_interface.dart (100%) rename flutter_modular/{lib/src => .src}/interfaces/route_guard.dart (100%) rename flutter_modular/{lib/src => .src}/modular_base.dart (100%) rename flutter_modular/{lib/src => .src}/modular_impl.dart (100%) rename flutter_modular/{lib/src => .src}/routers/modular_link.dart (100%) rename flutter_modular/{lib/src => .src}/routers/modular_page.dart (100%) rename flutter_modular/{lib/src => .src}/routers/modular_router.dart (100%) create mode 100644 flutter_modular/.src/test/modular_test_interface.dart create mode 100644 flutter_modular/.src/test/utils_test.dart rename flutter_modular/{lib/src => .src}/utils/modular_arguments.dart (100%) rename flutter_modular/{lib/src => .src}/widgets/modular_app.dart (100%) rename flutter_modular/{lib/src => .src}/widgets/modular_state.dart (100%) rename flutter_modular/{lib/src => .src}/widgets/router_outlet.dart (100%) rename flutter_modular/{lib/src => .src}/widgets/widget_module.dart (100%) create mode 100644 flutter_modular/lib/src/core/errors/errors.dart create mode 100644 flutter_modular/lib/src/core/inject/bind.dart create mode 100644 flutter_modular/lib/src/core/inject/inject.dart create mode 100644 flutter_modular/lib/src/core/interfaces/disposable.dart create mode 100644 flutter_modular/lib/src/core/interfaces/route_guard.dart create mode 100644 flutter_modular/lib/src/core/models/modular_arguments.dart create mode 100644 flutter_modular/lib/src/core/models/modular_router.dart create mode 100644 flutter_modular/lib/src/core/modules/child_module.dart create mode 100644 flutter_modular/lib/src/core/modules/main_module.dart rename flutter_modular/lib/src/{ => core}/transitions/page_transition.dart (96%) rename flutter_modular/lib/src/{ => core}/transitions/transitions.dart (99%) create mode 100644 flutter_modular/lib/src/presenters/interfaces/modular_interface.dart create mode 100644 flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart create mode 100644 flutter_modular/lib/src/presenters/modular_base.dart create mode 100644 flutter_modular/lib/src/presenters/modular_impl.dart create mode 100644 flutter_modular/lib/src/presenters/navigation/modular_page.dart create mode 100644 flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart create mode 100644 flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart create mode 100644 flutter_modular/lib/src/presenters/widgets/modular_app.dart create mode 100644 flutter_modular/lib/src/presenters/widgets/modular_state.dart create mode 100644 flutter_modular/lib/src/presenters/widgets/router_outlet.dart create mode 100644 flutter_modular/lib/src/presenters/widgets/widget_module.dart create mode 100644 flutter_modular/test/src/core/errors/errors_test.dart create mode 100644 flutter_modular/test/src/core/inject/bind_test.dart create mode 100644 flutter_modular/test/src/core/models/modular_arguments_test.dart create mode 100644 flutter_modular/test/src/core/models/modular_router_test.dart create mode 100644 flutter_modular/test/src/core/modules/child_module_test.dart create mode 100644 flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart diff --git a/flutter_modular/.backup/abstract_router_test.dart b/flutter_modular/.backup/abstract_router_test.dart deleted file mode 100644 index 9c15c13c..00000000 --- a/flutter_modular/.backup/abstract_router_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -// import 'package:flutter/material.dart'; -// import 'package:flutter_modular/flutter_modular.dart'; -// import 'package:flutter_test/flutter_test.dart'; - -// class DynamicModule extends ChildModule { -// @override -// List get binds => []; - -// @override -// List get routers => [ -// ModularRouter('/', child: (_, __) => Container()), -// ModularRouter('/home', child: (_, __) => Container()), -// ModularRouter('/product', child: (_, __) => Container()), -// ModularRouter('/product/:id', child: (_, __) => Container()), -// ModularRouter('/:id', child: (_, __) => Container()), -// ]; -// } - -// main() { -// setUpAll(() { -// Modular.init(DynamicModule()); -// }); - -// group("Dynamic router", () { -// test('Test Get ModularRouter', () { -// var router = Modular.selectRoute("/"); -// expect(router.routerName, "/"); -// }); -// test('Test Get ModularRouter dynamic', () { -// var router = Modular.selectRoute("/1"); -// expect(router.routerName, "/:id"); -// }); -// test('Test Get ModularRouter home', () { -// var router = Modular.selectRoute("/home"); -// expect(router.routerName, "/home"); -// }); - -// test('Test Get ModularRouter product', () { -// expect(Modular.selectRoute("/product")?.routerName, "/product"); -// }); -// test('Test Get ModularRouter product id', () { -// var router = Modular.selectRoute("/product/1"); -// expect(router.routerName, "/product/:id"); -// }); -// }); -// } diff --git a/flutter_modular/.backup/app/app_bloc.dart b/flutter_modular/.backup/app/app_bloc.dart deleted file mode 100644 index 696a4216..00000000 --- a/flutter_modular/.backup/app/app_bloc.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart' show Disposable; - -class AppBloc extends Disposable { - - - @override - void dispose() { - } - -} \ No newline at end of file diff --git a/flutter_modular/.backup/app/app_module.dart b/flutter_modular/.backup/app/app_module.dart deleted file mode 100644 index 3462c93d..00000000 --- a/flutter_modular/.backup/app/app_module.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'app_bloc.dart'; -import 'app_widget.dart'; -import 'modules/forbidden/forbidden_widget.dart'; -import 'modules/home/home_module.dart'; -import 'shared/ilocal_repository.dart'; -import 'shared/local_storage_shared.dart'; - -class AppModule extends MainModule { - @override - List get binds => [ - Bind((i) => AppBloc()), - Bind((i) => LocalStorageSharePreference()), - ]; - - @override - List get routers => [ - ModularRouter( - "/forbidden", - child: (_, args) => ForbiddenWidget(), - transition: TransitionType.fadeIn, - ), - ModularRouter( - "/home", - module: HomeModule(), - transition: TransitionType.fadeIn, - ), - // ModularRouter("/home", module: HomeModule()), - // ModularRouter("/prod", module: ProductModule()), - // ModularRouter("/homeTwo", module: HomeModule(), guards: [MyGuard()]), - ]; - - @override - Widget get bootstrap => AppWidget(); -} diff --git a/flutter_modular/.backup/app/app_module_test_modular.dart b/flutter_modular/.backup/app/app_module_test_modular.dart deleted file mode 100644 index 27fe3404..00000000 --- a/flutter_modular/.backup/app/app_module_test_modular.dart +++ /dev/null @@ -1,26 +0,0 @@ -// import '../../lib/flutter_modular_test.dart'; - -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'app_module.dart'; -import 'shared/ilocal_repository.dart'; -import 'shared/local_mock.dart'; - -class InitAppModuleHelper extends IModularTest { - final ModularTestType modularTestType; - - InitAppModuleHelper({this.modularTestType = ModularTestType.resetModules}); - - @override - List get binds => [ - Bind((i) => LocalMock()), - ]; - - @override - ChildModule get module => AppModule(); - - @override - IModularTest get modulardependency => null; -} diff --git a/flutter_modular/.backup/app/app_widget.dart b/flutter_modular/.backup/app/app_widget.dart deleted file mode 100644 index 2f637fa5..00000000 --- a/flutter_modular/.backup/app/app_widget.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -class AppWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - theme: ThemeData.dark(), - ).modular(); - } -} diff --git a/flutter_modular/.backup/app/guard/guard.dart b/flutter_modular/.backup/app/guard/guard.dart deleted file mode 100644 index e5137b68..00000000 --- a/flutter_modular/.backup/app/guard/guard.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter_modular/src/interfaces/route_guard.dart'; - -class MyGuard implements RouteGuard { - @override - bool canActivate(String url) { - return false; - } - - @override - List get executors => []; -} diff --git a/flutter_modular/.backup/app/modules/forbidden/forbidden_widget.dart b/flutter_modular/.backup/app/modules/forbidden/forbidden_widget.dart deleted file mode 100644 index a0f18153..00000000 --- a/flutter_modular/.backup/app/modules/forbidden/forbidden_widget.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/material.dart'; - -class ForbiddenWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("Acesso negado"), - ), - ); - } -} \ No newline at end of file diff --git a/flutter_modular/.backup/app/modules/home/home_bloc.dart b/flutter_modular/.backup/app/modules/home/home_bloc.dart deleted file mode 100644 index b79eb191..00000000 --- a/flutter_modular/.backup/app/modules/home/home_bloc.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import '../../app_bloc.dart'; - -class HomeBloc extends Disposable { - String testingText = 'testing inject'; - final AppBloc app; - - HomeBloc(this.app); - - @override - void dispose() { - debugPrint('call dispose'); - } -} diff --git a/flutter_modular/.backup/app/modules/home/home_module.dart b/flutter_modular/.backup/app/modules/home/home_module.dart deleted file mode 100644 index 47bb8995..00000000 --- a/flutter_modular/.backup/app/modules/home/home_module.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import '../../app_bloc.dart'; -import '../../shared/app_info.state.dart'; -import '../forbidden/forbidden_widget.dart'; -import 'home_bloc.dart'; -import 'home_widget.dart'; - -class HomeModule extends ChildModule { - @override - List get binds => [ - Bind((i) => AppState(), singleton: true), - Bind((i) => HomeBloc(i())), - Bind((i) => HomeBloc(i(defaultValue: AppBloc()))), - ]; - - @override - List get routers => [ - ModularRouter( - "/", - child: (_, args) => HomeWidget(), - children: [ - ModularRouter('/', child: (context, args) => ForbiddenWidget()), - ModularRouter('/product', - child: (context, args) => ForbiddenWidget()), - ], - ), - - // ModularRouter( - // "/forbidden2", - // child: (_, args) => ForbiddenWidget(), - // transition: TransitionType.fadeIn, - // guards: [MyGuard()], - // ), - // ModularRouter("/list/:id/:id2", child: (_, args) => HomeWidget()), - // ModularRouter("/product", module: ProductModule()), - // ModularRouter("/arguments", - // child: (_, args) => ArgumentsPage(id: args.data)), - // ModularRouter("/modularArguments", - // child: (_, args) => ModularArgumentsPage()), - ]; -} - -class ArgumentsPage extends StatelessWidget { - final int id; - - const ArgumentsPage({Key key, @required this.id}) : super(key: key); - @override - Widget build(BuildContext context) { - return Container( - child: Center( - child: Text("$id"), - ), - ); - } -} - -class ModularArgumentsPage extends StatefulWidget { - @override - _ModularArgumentsPageState createState() => _ModularArgumentsPageState(); -} - -class _ModularArgumentsPageState extends State { - int _id; - - @override - void initState() { - super.initState(); - // _id = Modular.args.data; - } - - @override - Widget build(BuildContext context) { - return Container( - child: Center( - child: Text("$_id"), - ), - ); - } -} diff --git a/flutter_modular/.backup/app/modules/home/home_module_test_modular.dart b/flutter_modular/.backup/app/modules/home/home_module_test_modular.dart deleted file mode 100644 index 975e931a..00000000 --- a/flutter_modular/.backup/app/modules/home/home_module_test_modular.dart +++ /dev/null @@ -1,23 +0,0 @@ -// import '../../lib/flutter_modular_test.dart'; - -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; - -import '../../app_module_test_modular.dart'; -import 'home_module.dart'; - -class InitHomeModuleHelper extends IModularTest { - final ModularTestType modularTestType; - - InitHomeModuleHelper({this.modularTestType = ModularTestType.resetModules}); - - @override - List get binds => []; - - @override - ChildModule get module => HomeModule(); - - @override - IModularTest get modulardependency => InitAppModuleHelper(); -} diff --git a/flutter_modular/.backup/app/modules/home/home_widget.dart b/flutter_modular/.backup/app/modules/home/home_widget.dart deleted file mode 100644 index 7d373c6f..00000000 --- a/flutter_modular/.backup/app/modules/home/home_widget.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'home_bloc.dart'; - -class HomeWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Container( - child: Text(Modular.get().testingText), - ); - } -} diff --git a/flutter_modular/.backup/app/modules/product/product_bloc.dart b/flutter_modular/.backup/app/modules/product/product_bloc.dart deleted file mode 100644 index 8ee8f71e..00000000 --- a/flutter_modular/.backup/app/modules/product/product_bloc.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -class ProductBloc extends Disposable { - - String testingText = 'testing inject'; - - @override - void dispose() { - debugPrint('call dispose'); - } - -} \ No newline at end of file diff --git a/flutter_modular/.backup/app/modules/product/product_module.dart b/flutter_modular/.backup/app/modules/product/product_module.dart deleted file mode 100644 index 11ea7967..00000000 --- a/flutter_modular/.backup/app/modules/product/product_module.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'product_bloc.dart'; - -class ProductModule extends ChildModule { - @override - List get binds => [ - Bind((i) => ProductBloc()), - ]; - - @override - List get routers => [ - ModularRouter("/:test", child: (_, args) => DetailsPage(id: 1)), - ModularRouter("/product", child: (_, args) => ProductPage()), - ]; -} - -class DetailsPage extends StatelessWidget { - final int id; - - const DetailsPage({Key key, this.id}) : super(key: key); - @override - Widget build(BuildContext context) { - return Container(); - } -} - -class ProductPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Container(); - } -} diff --git a/flutter_modular/.backup/app/modules/product/product_module_test_modular.dart b/flutter_modular/.backup/app/modules/product/product_module_test_modular.dart deleted file mode 100644 index 71e2157f..00000000 --- a/flutter_modular/.backup/app/modules/product/product_module_test_modular.dart +++ /dev/null @@ -1,25 +0,0 @@ -// import '../../lib/flutter_modular_test.dart'; - -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import '../../app_module_test_modular.dart'; -import 'product_module.dart'; - -class InitProductModuleHelper extends IModularTest { - final ModularTestType modularTestType; - - InitProductModuleHelper({ - this.modularTestType = ModularTestType.resetModules, - }); - - @override - List get binds => []; - - @override - ChildModule get module => ProductModule(); - - @override - IModularTest get modulardependency => InitAppModuleHelper(); -} diff --git a/flutter_modular/.backup/app/modules/product/product_widget.dart b/flutter_modular/.backup/app/modules/product/product_widget.dart deleted file mode 100644 index 3443ea9d..00000000 --- a/flutter_modular/.backup/app/modules/product/product_widget.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'product_bloc.dart'; - -class ProductWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Container( - child: Text(Modular.get().testingText), - ); - } -} diff --git a/flutter_modular/.backup/app/shared/app_info.state.dart b/flutter_modular/.backup/app/shared/app_info.state.dart deleted file mode 100644 index c4b5ccc6..00000000 --- a/flutter_modular/.backup/app/shared/app_info.state.dart +++ /dev/null @@ -1,9 +0,0 @@ -class AppState { - static int mainStateId = 0; - - int get stateId => mainStateId; - - AppState() { - mainStateId++; - } -} diff --git a/flutter_modular/.backup/app/shared/ilocal_repository.dart b/flutter_modular/.backup/app/shared/ilocal_repository.dart deleted file mode 100644 index b5258a22..00000000 --- a/flutter_modular/.backup/app/shared/ilocal_repository.dart +++ /dev/null @@ -1,5 +0,0 @@ -abstract class ILocalStorage { - Future get(String key); - Future put(String key, String value); - Future delete(String key); -} diff --git a/flutter_modular/.backup/app/shared/local_mock.dart b/flutter_modular/.backup/app/shared/local_mock.dart deleted file mode 100644 index 1113e0ae..00000000 --- a/flutter_modular/.backup/app/shared/local_mock.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'ilocal_repository.dart'; - -class LocalMock implements ILocalStorage { - @override - Future delete(String key) { - throw UnimplementedError(); - } - - @override - Future get(String key) { - throw UnimplementedError(); - } - - @override - Future put(String key, String value) { - throw UnimplementedError(); - } -} diff --git a/flutter_modular/.backup/app/shared/local_storage_shared.dart b/flutter_modular/.backup/app/shared/local_storage_shared.dart deleted file mode 100644 index b662ef1e..00000000 --- a/flutter_modular/.backup/app/shared/local_storage_shared.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'ilocal_repository.dart'; - -class LocalStorageSharePreference implements ILocalStorage { - @override - Future delete(String key) { - return null; - } - - @override - Future get(String key) { - return null; - } - - @override - Future put(String key, String value) { - return null; - } -} diff --git a/flutter_modular/.backup/bind_test.dart b/flutter_modular/.backup/bind_test.dart deleted file mode 100644 index 79b57f65..00000000 --- a/flutter_modular/.backup/bind_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -void main() { - group("Bind", () { - test('correct', () { - expect(Bind((i) => 'obs'), isA()); - expect(Bind((i) => 'obs', singleton: true, lazy: true), isA()); - expect(Bind((i) => 'obs', singleton: true, lazy: false), isA()); - expect(Bind((i) => 'obs', singleton: false, lazy: true), isA()); - }); - test('error', () { - expect( - () => Bind((i) => 'obs', singleton: false, lazy: false), - throwsAssertionError, - ); - }); - }); -} diff --git a/flutter_modular/.backup/modular_app_test.dart b/flutter_modular/.backup/modular_app_test.dart deleted file mode 100644 index ef11c8ed..00000000 --- a/flutter_modular/.backup/modular_app_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; - -void main() { - setUpAll(() {}); - -// group("Init module widget", () { -// testWidgets('ModularWidget', (WidgetTester tester) async { -// await tester.pumpWidget(ModularApp(module: AppModule(),)); -// final textInject = find.text('testing inject'); -// expect(textInject, findsOneWidget); -// }); -// }); -} diff --git a/flutter_modular/.backup/modular_extension_test.dart b/flutter_modular/.backup/modular_extension_test.dart deleted file mode 100644 index cdc020a4..00000000 --- a/flutter_modular/.backup/modular_extension_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -main() { - test('Initialized MaterialApp.modular sintaxe', () { - final theme = ThemeData.dark(); - final app = MaterialApp( - theme: theme, - ).modular(); - expect(app.theme, theme); - }); -} diff --git a/flutter_modular/.backup/modular_impl.dart b/flutter_modular/.backup/modular_impl.dart deleted file mode 100644 index bae895ad..00000000 --- a/flutter_modular/.backup/modular_impl.dart +++ /dev/null @@ -1 +0,0 @@ -main() {} diff --git a/flutter_modular/.backup/modular_inject_test.dart b/flutter_modular/.backup/modular_inject_test.dart deleted file mode 100644 index df1d2ee7..00000000 --- a/flutter_modular/.backup/modular_inject_test.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; - -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; - -import 'app/app_bloc.dart'; -import 'app/app_module.dart'; -import 'app/modules/home/home_bloc.dart'; -import 'app/modules/home/home_module.dart'; -import 'app/shared/app_info.state.dart'; -import 'app/shared/ilocal_repository.dart'; -import 'app/shared/local_storage_shared.dart'; - -void main() { - setUpAll(() { - initModules([ - AppModule(), - HomeModule(), - ]); - }); - - group("Inject", () { - test('Get withless module', () { - expect(Modular.get(), isA()); - expect(Modular.get(), isA()); - }); - - test('Get with module', () { - expect(Modular.get(module: 'AppModule'), isA()); - expect(Modular.get(module: 'HomeModule'), isA()); - }); - - test('Inject not found with module', () { - expect(() { - Modular.get(module: 'AppModule'); - }, throwsA(isA())); - expect(() { - Modular.get(module: 'HomeModule'); - }, throwsA(isA())); - }); - - test('Inject not found withless module', () { - expect(Modular.get, throwsA(isA())); - }); - - test('Inject singleton does not create duplicated instances', () { - var firstState = Modular.get().stateId; - var secondState = Modular.get().stateId; - expect(firstState, secondState); - }); - - test('Get Interface', () { - expect(Modular.get(), - isA()); - expect(Modular.get(), isA()); - }); - }); -} diff --git a/flutter_modular/.backup/modular_module_test_interface_test.dart b/flutter_modular/.backup/modular_module_test_interface_test.dart deleted file mode 100644 index 310c8fdc..00000000 --- a/flutter_modular/.backup/modular_module_test_interface_test.dart +++ /dev/null @@ -1,256 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -import 'app/app_module_test_modular.dart'; -import 'app/modules/home/home_module.dart'; -import 'app/modules/home/home_module_test_modular.dart'; -import 'app/modules/home/home_widget.dart'; -import 'app/modules/product/product_module_test_modular.dart'; -import 'app/shared/app_info.state.dart'; -import 'app/shared/ilocal_repository.dart'; -import 'app/shared/local_mock.dart'; -import 'app/shared/local_storage_shared.dart'; - -class CustomModuleTestMock extends Mock implements IModularTest {} - -class CustomLocalStorage extends Mock implements ILocalStorage {} - -void main() { - group("change bind", () { - IModularTest appModularHelper = InitAppModuleHelper(); - setUp(() { - appModularHelper.load(); - }); - test('ILocalStorage is a LocalMock', () { - expect(Modular.get(), isA()); - }); - - tearDown(() { - appModularHelper.memoryManage(ModularTestType.resetModules); - }); - }); - group("IModuleTest", () { - ILocalStorage localStorageBeforeReload; - setUp(() { - InitAppModuleHelper().load(); - Modular.get(); - }); - - // ILocalStorage localStorageBeforeReload = ; - - test('ILocalStorage is not equal when reload by default', () { - final localStorageAfterReload = Modular.get(); - - expect(localStorageBeforeReload.hashCode, - isNot(equals(localStorageAfterReload.hashCode))); - }); - test('ILocalStorage is equals when keepModulesOnMemory', () { - localStorageBeforeReload = Modular.get(); - InitAppModuleHelper(modularTestType: ModularTestType.keepModulesOnMemory) - .load(); - final localStorageAfterReload = Modular.get(); - expect(localStorageBeforeReload.hashCode, - equals(localStorageAfterReload.hashCode)); - }); - test('ILocalStorage Change bind when load on runtime', () { - IModularTest modularTest = InitAppModuleHelper(); - modularTest.load(); - - final localStorageBeforeChangeBind = Modular.get(); - expect(localStorageBeforeChangeBind.runtimeType, equals(LocalMock)); - - modularTest.load(changeBinds: [ - Bind((i) => LocalStorageSharePreference()), - ]); - final localStorageAfterChangeBind = Modular.get(); - - expect(localStorageAfterChangeBind.runtimeType, - equals(LocalStorageSharePreference)); - }); - test('ILocalStorage getDendencies', () { - IModularTest modularTest = InitAppModuleHelper(); - - expect(modularTest.getDendencies(isLoadDependency: true), isNull); - expect( - modularTest.getDendencies( - changedependency: InitAppModuleHelper(), - isLoadDependency: true, - ), - isNotNull, - ); - }); - test('ILocalStorage getBinds', () { - IModularTest modularTest = InitAppModuleHelper(); - - expect(modularTest.getBinds([]).length, modularTest.binds.length); - expect(modularTest.getBinds(null), isNotEmpty); - expect(modularTest.getBinds(null).first, - isInstanceOf>()); - - final stringBind = Bind((i) => "teste"); - final changeBinds = [ - Bind((i) => LocalStorageSharePreference()), - stringBind, - ]; - - expect(modularTest.getBinds(changeBinds), containsAll(changeBinds)); - }); - test('ILocalStorage mergeBinds', () { - IModularTest modularTest = InitAppModuleHelper(); - final stringBind = Bind((i) => "teste"); - final changeBinds = [ - Bind((i) => LocalMock()), - ]; - final defaultBinds = [ - Bind((i) => LocalStorageSharePreference()), - stringBind, - ]; - - expect(modularTest.mergeBinds(changeBinds, defaultBinds), - containsAll([changeBinds.first, stringBind])); - expect(modularTest.mergeBinds(changeBinds, null), equals(changeBinds)); - expect(modularTest.mergeBinds(null, defaultBinds), equals(defaultBinds)); - expect(modularTest.mergeBinds(null, null), equals([])); - }); - test('ILocalStorage memoryManage', () { - IModularTest modularTest = InitAppModuleHelper(); - - modularTest.load(); - expect(Modular.get(), isNotNull); - - modularTest.memoryManage(ModularTestType.keepModulesOnMemory); - expect(Modular.get(), isNotNull); - - modularTest.memoryManage(ModularTestType.resetModules); - - expect( - Modular.get, - throwsA( - isInstanceOf(), - ), - ); - }); - test('ILocalStorage loadModularDependency', () { - IModularTest modularTest = InitAppModuleHelper(); - - final customModule = CustomModuleTestMock(); - when(customModule.load(changeBinds: anyNamed("changeBinds"))) - .thenReturn(() {}); - - modularTest.loadModularDependency( - isLoadDependency: true, - changeBinds: [], - dependency: customModule, - ); - verify(customModule.load(changeBinds: anyNamed("changeBinds"))).called(1); - - modularTest.loadModularDependency( - isLoadDependency: false, - changeBinds: [], - dependency: customModule, - ); - verifyNever(customModule.load(changeBinds: anyNamed("changeBinds"))); - }); - test('ILocalStorage load HomeModule', () { - IModularTest homeModuleTest = InitHomeModuleHelper(); - expect( - Modular.get, - throwsA( - isInstanceOf(), - ), - ); - - homeModuleTest.load(); - expect( - Modular.get(), - isNotNull, - ); - }); - - test('Changing binds of parent modules', () { - IModularTest homeModuleTest = InitHomeModuleHelper(); - - homeModuleTest.load(); - final instance = Modular.get(); - - expect( - instance, - isInstanceOf(), - ); - - homeModuleTest.load(changeBinds: [ - Bind( - (i) => CustomLocalStorage(), - ) - ]); - - expect( - Modular.get(), - isInstanceOf(), - ); - - homeModuleTest.load(changeBinds: [ - Bind( - (i) => "test", - ) - ]); - - expect( - Modular.get(), - isInstanceOf(), - ); - - expect( - Modular.get, - throwsA(isInstanceOf()), - ); - }); - - // tearDown(() { - // Modular.removeModule(app); - // }); - }); - group("navigation test", () { - // As both share the same parent, - // you can pass by changeDependency and it can load in a row - IModularTest modularProductTest = InitProductModuleHelper(); - setUp(() { - InitProductModuleHelper().load( - changedependency: InitHomeModuleHelper(), - ); - }); - testWidgets('on pushNamed modify actualRoute ', (tester) async { - await tester.pumpWidget(buildTestableWidget(HomeWidget())); - Modular.to.pushNamed('/product'); - expect(Modular.to.path, '/product'); - }); - tearDown(() { - modularProductTest.memoryManage(ModularTestType.resetModules); - }); - }); - group("arguments test", () { - IModularTest modularHomeTest = InitHomeModuleHelper(); - - setUpAll(() { - modularHomeTest.load(); - }); - testWidgets("Arguments Page id", (tester) async { - await tester.pumpWidget(buildTestableWidget(ArgumentsPage( - id: 10, - ))); - final titleFinder = find.text("10"); - expect(titleFinder, findsOneWidget); - }); - testWidgets("Modular Arguments Page id", (tester) async { - // Modular.arguments(data: 10); - await tester.pumpWidget(buildTestableWidget(ModularArgumentsPage())); - final titleFinder = find.text("10"); - expect(titleFinder, findsOneWidget); - }); - tearDownAll(() { - modularHomeTest.memoryManage(ModularTestType.resetModules); - }); - }); -} diff --git a/flutter_modular/.backup/modular_stack_overflow_test.dart b/flutter_modular/.backup/modular_stack_overflow_test.dart deleted file mode 100644 index 1ac4560a..00000000 --- a/flutter_modular/.backup/modular_stack_overflow_test.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - setUpAll(() { - initModule(ModuleStackOverflowMock()); - initModule(ModuleStackOverflowMockNotError()); - }); - - group("Stackoverflow", () { - test('Error in bind', () { - expect(Modular.get, throwsA(isA())); - }); - - test('Not Error', () { - expect( - Modular.get( - module: 'ModuleStackOverflowMockNotError'), - isA()); - }); - }); -} - -class ModuleStackOverflowMock extends ChildModule { - @override - List get binds => [ - Bind((i) => ObjectController(i.get())), - Bind((i) => ObjectRepository(i.get())), - ]; - - @override - List get routers => []; -} - -class ObjectController { - final ObjectRepository repo; - - ObjectController(this.repo); -} - -class ObjectRepository { - final ObjectController controller; - - ObjectRepository(this.controller); -} - -class ModuleStackOverflowMockNotError extends ChildModule { - @override - List get binds => [ - Bind((i) => ObjectRepository01()), - Bind((i) => ObjectRepository02(i.get())), - Bind((i) => ObjectRepository03( - i.get(), i.get())), - Bind((i) => HomeController(i.get())), - ]; - - @override - List get routers => []; -} - -class HomeController { - final ObjectRepository03 repo; - - HomeController(this.repo); -} - -class ObjectRepository01 {} - -class ObjectRepository02 { - final ObjectRepository01 controller; - - ObjectRepository02(this.controller); -} - -class ObjectRepository03 { - final ObjectRepository01 controller1; - final ObjectRepository02 controller2; - - ObjectRepository03(this.controller1, this.controller2); -} diff --git a/flutter_modular/.backup/modular_test.dart b/flutter_modular/.backup/modular_test.dart deleted file mode 100644 index 5c2d9dec..00000000 --- a/flutter_modular/.backup/modular_test.dart +++ /dev/null @@ -1,126 +0,0 @@ -// import 'package:flutter/widgets.dart'; -// import 'package:flutter_modular/flutter_modular.dart'; -// import 'package:flutter_test/flutter_test.dart'; - -// import 'app/app_module.dart'; - -// void main() { -// setUpAll(() { -// Modular.init(AppModule()); -// }); - -// group("Group router", () { -// test('Test Get ModularRouter', () { -// expect(Modular.selectRoute("/"), isA()); -// }); -// test('Test Get module ModularRouter', () { -// expect(Modular.selectRoute("home/"), isA()); -// expect(Modular.selectRoute("/home/"), isA()); -// var router = Modular.selectRoute("/home"); -// expect(router.routerName, '/'); -// }); - -// test('router empty', () { -// expect(() => Modular.selectRoute(""), throwsException); -// }); - -// test('prepare to regex', () { -// expect(Modular.prepareToRegex('/home/list/:id'), '/home/list/(.*?)'); -// expect(Modular.prepareToRegex('/home/list/:id/'), '/home/list/(.*?)/'); -// expect(Modular.prepareToRegex('/home/list/:id/item/:num'), -// '/home/list/(.*?)/item/(.*?)'); -// }); - -// test('search object ModularRouter to url', () { -// var router = -// ModularRouter('/home/list/:id', child: (_, __) => SizedBox.shrink()); - -// expect( -// Modular.searchRoute(router, "/home/list/:id", "/home/list/1"), true); -// expect(router.params['id'], "1"); - -// expect( -// Modular.searchRoute( -// router, "/home/list/:id/item/:num", "/home/list/1/item/2"), -// true); -// expect(router.params['id'], "1"); -// expect(router.params['num'], "2"); - -// expect( -// Modular.searchRoute( -// ModularRouter('/home/list', child: (_, __) => SizedBox.shrink()), -// "/home/list", -// "/home/list/1"), -// false); -// }); - -// test('search object ModularRouter to url String', () { -// var router = -// ModularRouter('/home/list/:id', child: (_, __) => SizedBox.shrink()); - -// expect( -// Modular.searchRoute(router, "/home/list/:id", "/home/list/01"), true); -// expect(router.params['id'], "01"); - -// expect( -// Modular.searchRoute( -// ModularRouter('/home/list', child: (_, __) => SizedBox.shrink()), -// "/home/list", -// "/home/list/01"), -// false); -// }); - -// test('router with params get', () { -// expect(Modular.selectRoute("/list/1/2"), isA()); -// expect(Modular.selectRoute("/home/test"), null); -// }); -// test('router with params get multiple', () { -// var a = Modular.selectRoute("/home/list/1/2"); -// expect(a, isA()); -// }); -// test('router with params get multiple 2 modules', () { -// expect(Modular.selectRoute("/home/product/"), isA()); -// }); - -// test('modulePath', () { -// var router = Modular.selectRoute("/home/product/"); - -// expect(router, isA()); -// expect(router.modulePath, "/home/product"); - -// router = Modular.selectRoute("/home/product/1"); -// expect(router, isA()); -// expect(router.modulePath, "/home/product"); -// }); - -// test('Convert type', () { -// expect(Modular.convertType("value"), isA()); -// expect(Modular.convertType("1"), isA()); -// expect(Modular.convertType("1.1"), isA()); -// expect(Modular.convertType("true"), isA()); -// }); - -// test('RouteGuard test', () { -// expect(() => Modular.selectRoute("/forbidden"), -// throwsA(isA())); -// }); -// test('RouteGuard other module', () { -// expect(() => Modular.selectRoute("/home/forbidden2"), -// throwsA(isA())); -// }); -// test('RouteGuard other module', () { -// expect(() => Modular.selectRoute("/home/forbidden2"), -// throwsA(isA())); -// }); - -// test('RouteGuard other module Two', () { -// expect(() => Modular.selectRoute("/homeTwo/forbidden2"), -// throwsA(isA())); -// }); - -// test('Get route correct', () { -// final router = Modular.selectRoute("/prod/product"); -// expect(router.routerName, "/product"); -// }); -// }); -// } diff --git a/flutter_modular/.backup/modular_test_test.dart b/flutter_modular/.backup/modular_test_test.dart deleted file mode 100644 index 8c230cea..00000000 --- a/flutter_modular/.backup/modular_test_test.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'app/app_module.dart'; -import 'app/modules/home/home_module.dart'; -import 'app/modules/home/home_widget.dart'; -import 'app/modules/product/product_module.dart'; -import 'app/shared/ilocal_repository.dart'; -import 'app/shared/local_mock.dart'; - -void main() { - group("change bind", () { - // final app = AppModule(); - setUp(() { - initModule(AppModule(), changeBinds: [ - Bind((i) => LocalMock()), - ]); - }); - test('ILocalStorage is a LocalMock', () { - expect(Modular.get(), isA()); - }); - tearDown(() { - // Modular.removeModule(app); - }); - }); - group("navigation test", () { - final app = AppModule(); - final home = HomeModule(); - final product = ProductModule(); - setUp(() { - initModule(app, initialModule: true); - initModules([home, product]); - }); - testWidgets('on pushNamed modify actualRoute ', (tester) async { - await tester.pumpWidget(buildTestableWidget(HomeWidget())); - Modular.to.pushNamed('/prod'); - expect(Modular.link.path, '/prod'); - }); - tearDown(() { - // Modular.removeModule(product); - // Modular.removeModule(home); - // Modular.removeModule(app); - }); - }); - group("arguments test", () { - final app = AppModule(); - setUpAll(() { - initModule(app, initialModule: true); - }); - testWidgets("Arguments Page id", (tester) async { - await tester.pumpWidget(buildTestableWidget(ArgumentsPage( - id: 10, - ))); - final titleFinder = find.text("10"); - expect(titleFinder, findsOneWidget); - }); - testWidgets("Modular Arguments Page id", (tester) async { - // Modular.arguments(data: 10); - await tester.pumpWidget(buildTestableWidget(ModularArgumentsPage())); - final titleFinder = find.text("10"); - expect(titleFinder, findsOneWidget); - }); - tearDownAll(() { - // Modular.removeModule(home); - // Modular.removeModule(app); - }); - }); -} diff --git a/flutter_modular/.backup/modular_widget_test.dart b/flutter_modular/.backup/modular_widget_test.dart deleted file mode 100644 index a63ac62f..00000000 --- a/flutter_modular/.backup/modular_widget_test.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -void main() { - setUpAll(() { - initModule(OtherWidget()); - }); - - group("Init ModularWidget", () { - test('get ObjectTest', () { - expect(Modular.get(), isA()); - }); - }); -} - -class OtherWidget extends WidgetModule { - @override - List get binds => [ - Bind((i) => ObjectTest()), - Bind((i) => OtherWidgetNotLazyError(), lazy: false), - ]; - - @override - Widget get view => throw UnimplementedError(); -} - -class OtherWidgetNotLazyError { - OtherWidgetNotLazyError() { - debugPrint('Not lazy'); - } -} - -class ObjectTest { - ObjectTest() { - debugPrint('lazy'); - } -} diff --git a/flutter_modular/.backup/new_route_test.dart b/flutter_modular/.backup/new_route_test.dart deleted file mode 100644 index b5db7f9d..00000000 --- a/flutter_modular/.backup/new_route_test.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'app/app_module.dart'; - -main() { - testWidgets('Button is present and triggers navigation after tapped', - (tester) async { - await tester.runAsync(() async { - await tester.pumpWidget(ModularApp( - module: AppModule(), - )); - - await routerDelegate.pushNamed('/forbidden'); - await tester.pump(); - //how to test navigator? - await Future.delayed(Duration(seconds: 2)); - Modular.to.pop('Teste pop'); - await tester.pump(); - }); - }); -} diff --git a/flutter_modular/.backup/routers/router_test.dart b/flutter_modular/.backup/routers/router_test.dart deleted file mode 100644 index 0710f529..00000000 --- a/flutter_modular/.backup/routers/router_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_test/flutter_test.dart'; - -class TestModule extends ChildModule { - @override - List get binds => []; - - @override - List get routers => []; -} - -void main() { - test('throws assertionError routeName is null', () { - expect(() => ModularRouter(null), throwsAssertionError); - }); - - test('throws ArgumentError if module or child was not provide', () { - expect(() => ModularRouter('/'), throwsArgumentError); - }); - - test('throws ArgumentError if both the module and child was provided', () { - expect(() { - ModularRouter('/', - module: TestModule(), child: (_, __) => SizedBox.shrink()); - }, throwsArgumentError); - }); - - test('throws ArgumentError if transaction is null', () { - expect(() { - ModularRouter( - '/', - child: (_, __) => SizedBox.shrink(), - transition: null, - ); - }, throwsArgumentError); - }); -} diff --git a/flutter_modular/.backup/transition/transitions_test.dart b/flutter_modular/.backup/transition/transitions_test.dart deleted file mode 100644 index 5e5e30a8..00000000 --- a/flutter_modular/.backup/transition/transitions_test.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/transitions/transitions.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test('fadeInTransition', () { - var r = fadeInTransition((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('noTransition', () { - var r = noTransition((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('rightToLeft', () { - var r = rightToLeft((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('leftToRight', () { - var r = leftToRight((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('upToDown', () { - var r = upToDown((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('downToUp', () { - var r = downToUp((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('scale', () { - var r = scale((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - - test('rotate', () { - var r = rotate((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('size', () { - var r = size((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('rightToLeftWithFade', () { - var r = - rightToLeftWithFade((context, args) => Container(), null, null, null); - expect(r, isA()); - }); - test('leftToRightWithFade', () { - var r = - leftToRightWithFade((context, args) => Container(), null, null, null); - expect(r, isA()); - }); -} diff --git a/flutter_modular/lib/src/delegates/modular_route_information_parser.dart b/flutter_modular/.src/delegates/modular_route_information_parser.dart similarity index 100% rename from flutter_modular/lib/src/delegates/modular_route_information_parser.dart rename to flutter_modular/.src/delegates/modular_route_information_parser.dart diff --git a/flutter_modular/lib/src/delegates/modular_router_delegate.dart b/flutter_modular/.src/delegates/modular_router_delegate.dart similarity index 100% rename from flutter_modular/lib/src/delegates/modular_router_delegate.dart rename to flutter_modular/.src/delegates/modular_router_delegate.dart diff --git a/flutter_modular/lib/src/exceptions/modular_error.dart b/flutter_modular/.src/exceptions/modular_error.dart similarity index 100% rename from flutter_modular/lib/src/exceptions/modular_error.dart rename to flutter_modular/.src/exceptions/modular_error.dart diff --git a/flutter_modular/lib/src/inject/bind.dart b/flutter_modular/.src/inject/bind.dart similarity index 100% rename from flutter_modular/lib/src/inject/bind.dart rename to flutter_modular/.src/inject/bind.dart diff --git a/flutter_modular/lib/src/inject/inject.dart b/flutter_modular/.src/inject/inject.dart similarity index 100% rename from flutter_modular/lib/src/inject/inject.dart rename to flutter_modular/.src/inject/inject.dart diff --git a/flutter_modular/lib/src/interfaces/child_module.dart b/flutter_modular/.src/interfaces/child_module.dart similarity index 100% rename from flutter_modular/lib/src/interfaces/child_module.dart rename to flutter_modular/.src/interfaces/child_module.dart diff --git a/flutter_modular/lib/src/interfaces/disposable.dart b/flutter_modular/.src/interfaces/disposable.dart similarity index 100% rename from flutter_modular/lib/src/interfaces/disposable.dart rename to flutter_modular/.src/interfaces/disposable.dart diff --git a/flutter_modular/lib/src/interfaces/main_module.dart b/flutter_modular/.src/interfaces/main_module.dart similarity index 100% rename from flutter_modular/lib/src/interfaces/main_module.dart rename to flutter_modular/.src/interfaces/main_module.dart diff --git a/flutter_modular/lib/src/interfaces/modular_interface.dart b/flutter_modular/.src/interfaces/modular_interface.dart similarity index 100% rename from flutter_modular/lib/src/interfaces/modular_interface.dart rename to flutter_modular/.src/interfaces/modular_interface.dart diff --git a/flutter_modular/lib/src/interfaces/modular_navigator_interface.dart b/flutter_modular/.src/interfaces/modular_navigator_interface.dart similarity index 100% rename from flutter_modular/lib/src/interfaces/modular_navigator_interface.dart rename to flutter_modular/.src/interfaces/modular_navigator_interface.dart diff --git a/flutter_modular/lib/src/interfaces/route_guard.dart b/flutter_modular/.src/interfaces/route_guard.dart similarity index 100% rename from flutter_modular/lib/src/interfaces/route_guard.dart rename to flutter_modular/.src/interfaces/route_guard.dart diff --git a/flutter_modular/lib/src/modular_base.dart b/flutter_modular/.src/modular_base.dart similarity index 100% rename from flutter_modular/lib/src/modular_base.dart rename to flutter_modular/.src/modular_base.dart diff --git a/flutter_modular/lib/src/modular_impl.dart b/flutter_modular/.src/modular_impl.dart similarity index 100% rename from flutter_modular/lib/src/modular_impl.dart rename to flutter_modular/.src/modular_impl.dart diff --git a/flutter_modular/lib/src/routers/modular_link.dart b/flutter_modular/.src/routers/modular_link.dart similarity index 100% rename from flutter_modular/lib/src/routers/modular_link.dart rename to flutter_modular/.src/routers/modular_link.dart diff --git a/flutter_modular/lib/src/routers/modular_page.dart b/flutter_modular/.src/routers/modular_page.dart similarity index 100% rename from flutter_modular/lib/src/routers/modular_page.dart rename to flutter_modular/.src/routers/modular_page.dart diff --git a/flutter_modular/lib/src/routers/modular_router.dart b/flutter_modular/.src/routers/modular_router.dart similarity index 100% rename from flutter_modular/lib/src/routers/modular_router.dart rename to flutter_modular/.src/routers/modular_router.dart diff --git a/flutter_modular/.src/test/modular_test_interface.dart b/flutter_modular/.src/test/modular_test_interface.dart new file mode 100644 index 00000000..7ce7ce46 --- /dev/null +++ b/flutter_modular/.src/test/modular_test_interface.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import '../../flutter_modular.dart'; +import '../../flutter_modular_test.dart'; + +enum ModularTestType { resetModules, keepModulesOnMemory } + +abstract class IModularTest { + final ModularTestType modularTestType; + IModularTest({this.modularTestType = ModularTestType.resetModules}); + + ChildModule get module; + List get binds; + IModularTest get modulardependency; + + void load({ + IModularTest? changedependency, + List? changeBinds, + bool isLoadDependency = true, + }) { + final dependency = getDendencies( + changedependency: changedependency, + isLoadDependency: isLoadDependency, + ); + final binds = getBinds(changeBinds); + memoryManage(modularTestType); + loadModularDependency( + isLoadDependency: isLoadDependency, + changeBinds: changeBinds, + dependency: dependency, + ); + + initModule(module, changeBinds: binds, initialModule: isMainModule); + } + + @visibleForTesting + IModularTest getDendencies({ + IModularTest? changedependency, + required bool isLoadDependency, + }) { + changedependency ??= modulardependency; + + assert( + !_isDependencyRequired(changedependency, isLoadDependency), + "Dependency must not be null when isLoadDependency is true", + ); + return changedependency; + } + + bool _isDependencyRequired(IModularTest? dependency, bool isLoadDependency) => + dependency == null && isLoadDependency && isMainModule; + + @visibleForTesting + List getBinds(List? changeBinds) { + final mergedChangeBinds = mergeBinds(changeBinds, binds); + + return mergedChangeBinds; + } + + @visibleForTesting + List mergeBinds(List? changeBinds, List? defaultBinds) { + final resultBinds = defaultBinds ?? []; + + for (var bind in (changeBinds ?? [])) { + var changedBind = resultBinds.firstWhere( + (item) => item.runtimeType == bind.runtimeType, + orElse: () => BindEmpty(), + ); + + if (changedBind is! BindEmpty) resultBinds.remove(changedBind); + resultBinds.add(bind); + } + + return resultBinds; + } + + @visibleForTesting + void memoryManage(ModularTestType modularTestType) { + if (modularTestType == ModularTestType.resetModules) { + // Modular.removeModule(module); + } + } + + @visibleForTesting + void loadModularDependency({ + required bool isLoadDependency, + required List? changeBinds, + required IModularTest? dependency, + }) { + if (isLoadDependency && dependency != null) { + dependency.load(changeBinds: changeBinds); + } + } + + bool get isMainModule => !(module is MainModule); +} diff --git a/flutter_modular/.src/test/utils_test.dart b/flutter_modular/.src/test/utils_test.dart new file mode 100644 index 00000000..981eee22 --- /dev/null +++ b/flutter_modular/.src/test/utils_test.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +import '../../flutter_modular.dart'; + +void initModule(ChildModule module, + {List changeBinds = const [], bool initialModule = false}) { + //Modular.debugMode = false; + final list = module.binds; + final changedList = List.from(list); + for (var item in list) { + var dep = (changeBinds).firstWhere((dep) { + return item.runtimeType == dep.runtimeType; + }, orElse: () => BindEmpty()); + if (dep is BindEmpty) { + changedList.remove(item); + changedList.add(dep); + } + } + module.changeBinds(changedList); + if (initialModule) { + // Modular.init(module); + } else { + // Modular.bindModule(module); + } +} + +void initModules(List modules, + {List changeBinds = const []}) { + for (var module in modules) { + initModule(module, changeBinds: changeBinds); + } +} + +Widget buildTestableWidget(Widget widget) { + return MediaQuery( + data: MediaQueryData(), + child: MaterialApp( + home: widget, + initialRoute: '/', + // navigatorKey: Modular.navigatorKey, + // onGenerateRoute: Modular.generateRoute, + ), + ); +} diff --git a/flutter_modular/lib/src/utils/modular_arguments.dart b/flutter_modular/.src/utils/modular_arguments.dart similarity index 100% rename from flutter_modular/lib/src/utils/modular_arguments.dart rename to flutter_modular/.src/utils/modular_arguments.dart diff --git a/flutter_modular/lib/src/widgets/modular_app.dart b/flutter_modular/.src/widgets/modular_app.dart similarity index 100% rename from flutter_modular/lib/src/widgets/modular_app.dart rename to flutter_modular/.src/widgets/modular_app.dart diff --git a/flutter_modular/lib/src/widgets/modular_state.dart b/flutter_modular/.src/widgets/modular_state.dart similarity index 100% rename from flutter_modular/lib/src/widgets/modular_state.dart rename to flutter_modular/.src/widgets/modular_state.dart diff --git a/flutter_modular/lib/src/widgets/router_outlet.dart b/flutter_modular/.src/widgets/router_outlet.dart similarity index 100% rename from flutter_modular/lib/src/widgets/router_outlet.dart rename to flutter_modular/.src/widgets/router_outlet.dart diff --git a/flutter_modular/lib/src/widgets/widget_module.dart b/flutter_modular/.src/widgets/widget_module.dart similarity index 100% rename from flutter_modular/lib/src/widgets/widget_module.dart rename to flutter_modular/.src/widgets/widget_module.dart diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 5fd225b1..559f07ef 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -1,18 +1,16 @@ library flutter_modular; export 'flutter_modular_annotations.dart'; -export 'src/exceptions/modular_error.dart'; -export 'src/inject/bind.dart'; -export 'src/inject/inject.dart'; -export 'src/interfaces/child_module.dart'; -export 'src/interfaces/disposable.dart'; -export 'src/interfaces/main_module.dart'; -export 'src/interfaces/modular_navigator_interface.dart'; -export 'src/interfaces/route_guard.dart'; -export 'src/modular_base.dart'; -export 'src/routers/modular_router.dart'; -export 'src/utils/modular_arguments.dart'; -export 'src/widgets/modular_app.dart'; -export 'src/widgets/modular_state.dart'; -export 'src/widgets/router_outlet.dart'; -export 'src/widgets/widget_module.dart'; +export 'src/core/inject/bind.dart'; +export 'src/core/inject/inject.dart'; +export 'src/core/interfaces/disposable.dart'; +export 'src/core/interfaces/route_guard.dart'; +export 'src/core/models/modular_arguments.dart'; +export 'src/core/models/modular_router.dart'; +export 'src/core/modules/child_module.dart'; +export 'src/core/modules/main_module.dart'; +export 'src/presenters/modular_base.dart'; +export 'src/presenters/widgets/modular_app.dart'; +export 'src/presenters/widgets/modular_state.dart'; +export 'src/presenters/widgets/router_outlet.dart'; +export 'src/presenters/widgets/widget_module.dart'; diff --git a/flutter_modular/lib/src/core/errors/errors.dart b/flutter_modular/lib/src/core/errors/errors.dart new file mode 100644 index 00000000..df98b5b8 --- /dev/null +++ b/flutter_modular/lib/src/core/errors/errors.dart @@ -0,0 +1,13 @@ +abstract class ModularFailure implements Exception { + final String message; + ModularFailure(this.message); + + @override + String toString() { + return "$runtimeType: $message"; + } +} + +class ModularError extends ModularFailure { + ModularError(String message) : super(message); +} diff --git a/flutter_modular/lib/src/core/inject/bind.dart b/flutter_modular/lib/src/core/inject/bind.dart new file mode 100644 index 00000000..e1fe65c4 --- /dev/null +++ b/flutter_modular/lib/src/core/inject/bind.dart @@ -0,0 +1,58 @@ +import 'inject.dart'; + +class Bind { + final T Function(Inject i) inject; + + ///single instance object? + final bool singleton; + + ///When 'true', the object is instantiated only the first time it is called. + ///When 'false', the object is instantiated along with the module. + final bool lazy; + + Bind(this.inject, {this.singleton = true, this.lazy = true}) + : assert((singleton || lazy), + r"'singleton' can't be false if 'lazy' is also false"); + + ///Bind an already exist 'Instance' of object.. + factory Bind.instance(T instance) { + return Bind((i) => instance, singleton: false, lazy: true); + } + + ///Bind a 'Singleton' class. + ///Built together with the module. + ///The instance will always be the same. + factory Bind.singleton(T Function(Inject i) inject) { + return Bind(inject, singleton: true, lazy: false); + } + + ///Bind a 'Lazy Singleton' class. + ///Built only when called the first time using Modular.get. + ///The instance will always be the same. + factory Bind.lazySingleton(T Function(Inject i) inject) { + return Bind(inject, singleton: true, lazy: true); + } + + ///Bind a factory. Always a new constructor when calling Modular.get + factory Bind.factory(T Function(Inject i) inject) { + return Bind(inject, singleton: false, lazy: true); + } +} + +class BindInject extends Bind { + final T Function(Inject i) inject; + + ///single instance object? + final bool singleton; + + ///When 'true', the object is instantiated only the first time it is called. + ///When 'false', the object is instantiated along with the module. + final bool lazy; + + BindInject(this.inject, {this.singleton = true, this.lazy = true}) + : super(inject, singleton: singleton, lazy: lazy); +} + +class BindEmpty extends Bind { + BindEmpty() : super((e) => Object()); +} diff --git a/flutter_modular/lib/src/core/inject/inject.dart b/flutter_modular/lib/src/core/inject/inject.dart new file mode 100644 index 00000000..8a9df0bb --- /dev/null +++ b/flutter_modular/lib/src/core/inject/inject.dart @@ -0,0 +1,10 @@ +class Inject { + ///!!!!NOT RECOMMENDED USE!!!! + ///Bind has access to the arguments coming from the routes. + ///If you need specific access, do it through functions. + @deprecated + Map? params = {}; + final List typesInRequest; + + Inject({this.params, this.typesInRequest = const []}); +} diff --git a/flutter_modular/lib/src/core/interfaces/disposable.dart b/flutter_modular/lib/src/core/interfaces/disposable.dart new file mode 100644 index 00000000..744d7ef0 --- /dev/null +++ b/flutter_modular/lib/src/core/interfaces/disposable.dart @@ -0,0 +1,7 @@ +/// A class which implements [Disposable] can be disposed automatically +/// once user leaves a Module +//ignore:one_member_abstracts +abstract class Disposable { + /// Disposes controllers, streams, etc. + void dispose(); +} diff --git a/flutter_modular/lib/src/core/interfaces/route_guard.dart b/flutter_modular/lib/src/core/interfaces/route_guard.dart new file mode 100644 index 00000000..4ec8e028 --- /dev/null +++ b/flutter_modular/lib/src/core/interfaces/route_guard.dart @@ -0,0 +1,7 @@ +//ignore:one_member_abstracts + +import '../models/modular_router.dart'; + +mixin RouteGuard { + Future canActivate(String path, ModularRouter router); +} diff --git a/flutter_modular/lib/src/core/models/modular_arguments.dart b/flutter_modular/lib/src/core/models/modular_arguments.dart new file mode 100644 index 00000000..c26a882e --- /dev/null +++ b/flutter_modular/lib/src/core/models/modular_arguments.dart @@ -0,0 +1,17 @@ +class ModularArguments { + final Map? params; + final dynamic? data; + + const ModularArguments({this.params, this.data}); + + ModularArguments copyWith({Map? params, dynamic? data}) { + return ModularArguments( + params: params ?? this.params, + data: data ?? this.data, + ); + } + + factory ModularArguments.empty() { + return ModularArguments(); + } +} diff --git a/flutter_modular/lib/src/core/models/modular_router.dart b/flutter_modular/lib/src/core/models/modular_router.dart new file mode 100644 index 00000000..c24d2702 --- /dev/null +++ b/flutter_modular/lib/src/core/models/modular_router.dart @@ -0,0 +1,292 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../interfaces/route_guard.dart'; +import '../modules/child_module.dart'; +import '../transitions/transitions.dart'; +import 'modular_arguments.dart'; + +typedef RouteBuilder = MaterialPageRoute Function( + WidgetBuilder, RouteSettings); +typedef ModularChild = Widget Function( + BuildContext context, ModularArguments? args); + +class ModularRouter { + final ChildModule? currentModule; + + final ModularArguments? args; + + final List children; + + final String? path; + + /// + /// Paramenter name: [routerName] + /// + /// Name for your route + /// + /// Type: String + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final String routerName; + + /// + /// Paramenter name: [child] + /// + /// The widget will be displayed + /// + /// Type: Widget + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + + final ModularChild? child; + + /// + /// Paramenter name: [module] + /// + /// The module will be loaded + /// + /// Type: ChildModule + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final ChildModule? module; + + /// + /// Paramenter name: [params] + /// + /// The parameters that can be transferred to another screen + /// + /// Type: Map + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final Map? params; + + /// + /// Paramenter name: [guards] + /// + /// Route guards are middleware-like objects + /// + /// that allow you to control the access of a given route from other route. + /// + /// You can implement a route guard by making a class that implements RouteGuard. + /// + /// Type: List + /// + /// Example: + /// ```dart + ///class MyGuard implements RouteGuard { + /// @override + /// Future canActivate(String url, ModularRouter router) { + /// if (url != '/admin'){ + /// // Return `true` to allow access + /// return true; + /// } else { + /// // Return `false` to disallow access + /// return false + /// } + /// } + ///} + /// ``` + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + + final List? guards; + + /// + /// Paramenter name: [transition] + /// + /// Used to animate the transition from one screen to another + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final TransitionType transition; + + /// + /// Paramenter name: [customTransiton] + /// + /// PS: For [customTransition] to work, + /// + /// you must set the [transition] parameter for + /// ```dart + /// transition.custom, + /// ``` + /// + /// Example: Using just First Animation + /// ```dart + /// customTransition: CustomTransition( + /// transitionBuilder: (context, animation, secondaryAnimation, child) { + /// return SlideTransition( + /// transformHitTests: false, + /// position: Tween( + /// begin: const Offset(0.0, 1.0), + /// end: Offset.zero, + /// ).chain(CurveTween(curve: Curves.ease)).animate(animation), + /// child: child); + /// }, + /// ), + /// ``` + + /// Example: Using just secondaryAnimation + /// ```dart + /// customTransition: CustomTransition( + /// transitionBuilder: (context, animation, secondaryAnimation, child) { + /// return SlideTransition( + /// transformHitTests: false, + /// position: Tween( + /// begin: const Offset(0.0, 1.0), + /// end: Offset.zero, + /// ).chain(CurveTween(curve: Curves.ease)).animate(animation), + /// child: SlideTransition( + /// transformHitTests: false, + /// position: Tween( + /// begin: Offset.zero, + /// end: const Offset(0.0, -1.0), + /// ).chain(CurveTween(curve: Curves.ease)).animate(secondaryAnimation), + /// child: child, + /// ), + /// ); + /// }, + /// ), + /// ``` + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final CustomTransition? customTransition; + + /// + /// Paramenter name: [transition] + /// + /// Used to animate the transition from one screen to another + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final RouteBuilder? routeGenerator; + final String? modulePath; + final Duration duration; + final Map< + TransitionType, + PageRouteBuilder Function( + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, + Duration transitionDuration, + RouteSettings settings, + )> transitions = { + TransitionType.fadeIn: fadeInTransition, + TransitionType.noTransition: noTransition, + TransitionType.rightToLeft: rightToLeft, + TransitionType.leftToRight: leftToRight, + TransitionType.upToDown: upToDown, + TransitionType.downToUp: downToUp, + TransitionType.scale: scale, + TransitionType.rotate: rotate, + TransitionType.size: size, + TransitionType.rightToLeftWithFade: rightToLeftWithFade, + TransitionType.leftToRightWithFade: leftToRightWithFade, + }; + + ModularRouter( + this.routerName, { + this.path = '/', + this.children = const [], + this.args = const ModularArguments(), + this.module, + this.child, + this.guards, + this.params, + this.currentModule, + this.transition = TransitionType.defaultTransition, + this.routeGenerator, + this.customTransition, + this.duration = const Duration(milliseconds: 300), + this.modulePath = '/', + }) : assert(module == null ? true : children.isEmpty, + 'Módulo não pode conter rotas aninhadas (children)'), + assert((transition == TransitionType.custom && + customTransition != null) || + transition != TransitionType.custom && customTransition == null), + assert((module == null && child != null) || + (module != null && child == null)); + + ModularRouter copyWith( + {ModularChild? child, + String? routerName, + ChildModule? module, + List? children, + ChildModule? currentModule, + Map? params, + List? guards, + TransitionType? transition, + RouteBuilder? routeGenerator, + String? modulePath, + String? path, + Duration? duration, + Completer? popRoute, + ModularArguments? args, + CustomTransition? customTransition}) { + return ModularRouter( + routerName ?? this.routerName, + child: child ?? this.child, + args: args ?? this.args, + children: children ?? this.children, + module: module ?? this.module, + currentModule: currentModule ?? this.currentModule, + params: params ?? this.params, + modulePath: modulePath ?? this.modulePath, + path: path ?? this.path, + guards: guards ?? this.guards, + duration: duration ?? this.duration, + routeGenerator: routeGenerator ?? this.routeGenerator, + transition: transition ?? this.transition, + customTransition: customTransition ?? this.customTransition, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object o) { + if (identical(this, o)) return true; + + return o is ModularRouter && + o.modulePath == modulePath && + o.routerName == routerName && + o.module == module; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return currentModule.hashCode ^ routerName.hashCode; + } +} + +enum TransitionType { + defaultTransition, + fadeIn, + noTransition, + rightToLeft, + leftToRight, + upToDown, + downToUp, + scale, + rotate, + size, + rightToLeftWithFade, + leftToRightWithFade, + custom, +} + +class CustomTransition { + final Widget Function( + BuildContext, Animation, Animation, Widget) + transitionBuilder; + final Duration transitionDuration; + + CustomTransition( + {required this.transitionBuilder, + this.transitionDuration = const Duration(milliseconds: 300)}); +} diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/modules/child_module.dart new file mode 100644 index 00000000..5dde4318 --- /dev/null +++ b/flutter_modular/lib/src/core/modules/child_module.dart @@ -0,0 +1,116 @@ +import 'package:flutter/widgets.dart'; + +import '../errors/errors.dart'; +import '../inject/bind.dart'; +import '../inject/inject.dart'; +import '../interfaces/disposable.dart'; +import '../models/modular_router.dart'; + +abstract class ChildModule { + late final List binds; + late final List routers; + + ChildModule(); + + @visibleForTesting + void changeBinds(List b) { + binds.clear(); + binds.addAll(b); + } + + final List paths = []; + + final Map _singletonBinds = {}; + + T? getBind( + {Map? params, required List typesInRequest}) { + T bindValue; + var type = _getInjectType(); + if (_singletonBinds.containsKey(type)) { + bindValue = _singletonBinds[type]; + return bindValue; + } + + var bind = binds.firstWhere((b) => b.inject is T Function(Inject), + orElse: () => BindEmpty()); + if (bind is BindEmpty) { + typesInRequest.remove(type); + return null; + } + + if (typesInRequest.contains(type)) { + throw ModularError(''' +Recursive calls detected. This can cause StackOverflow. +Check the Binds of the $runtimeType module: +*** +${typesInRequest.join('\n')} +*** + + '''); + } else { + typesInRequest.add(type); + } + + bindValue = + bind.inject(Inject(params: params, typesInRequest: typesInRequest)); + if (bind.singleton) { + _singletonBinds[type] = bindValue; + } + + typesInRequest.remove(type); + return bindValue; + } + + /// Dispose bind from the memory + bool remove() { + final type = _getInjectType(); + if (_singletonBinds.containsKey(type)) { + var inject = _singletonBinds[type]; + _callDispose(inject); + _singletonBinds.remove(type); + return true; + } else { + return false; + } + } + + _callDispose(dynamic bind) { + if (bind is Disposable || bind is ChangeNotifier) { + bind.dispose(); + return; + } else if (bind is Sink) { + bind.close(); + return; + } + } + + /// Dispose all bind from the memory + void cleanInjects() { + for (final key in _singletonBinds.keys) { + var _bind = _singletonBinds[key]; + _callDispose(_bind); + } + _singletonBinds.clear(); + } + + Type _getInjectType() { + var foundType = B; + _singletonBinds.forEach((key, value) { + if (value is B) { + foundType = key; + } + }); + + return foundType; + } + + /// Create a instance of all binds isn't lazy Loaded + void instance() { + for (final bindElement in binds) { + if (!bindElement.lazy) { + var b = bindElement.inject(Inject()); + _singletonBinds[b.runtimeType] = b; + } + } + } +} diff --git a/flutter_modular/lib/src/core/modules/main_module.dart b/flutter_modular/lib/src/core/modules/main_module.dart new file mode 100644 index 00000000..f3f870d0 --- /dev/null +++ b/flutter_modular/lib/src/core/modules/main_module.dart @@ -0,0 +1,7 @@ +import 'package:flutter/widgets.dart'; + +import 'child_module.dart'; + +abstract class MainModule extends ChildModule { + Widget get bootstrap; +} diff --git a/flutter_modular/lib/src/transitions/page_transition.dart b/flutter_modular/lib/src/core/transitions/page_transition.dart similarity index 96% rename from flutter_modular/lib/src/transitions/page_transition.dart rename to flutter_modular/lib/src/core/transitions/page_transition.dart index a25f5df8..f66bfd01 100644 --- a/flutter_modular/lib/src/transitions/page_transition.dart +++ b/flutter_modular/lib/src/core/transitions/page_transition.dart @@ -41,7 +41,6 @@ class PageTransition extends PageRouteBuilder { opacity: animation, child: child, ); - break; case PageTransitionType.rightToLeft: return SlideTransition( transformHitTests: false, @@ -58,7 +57,7 @@ class PageTransition extends PageRouteBuilder { child: child, ), ); - break; + case PageTransitionType.leftToRight: return SlideTransition( transformHitTests: false, @@ -75,7 +74,6 @@ class PageTransition extends PageRouteBuilder { child: child, ), ); - break; case PageTransitionType.upToDown: return SlideTransition( transformHitTests: false, @@ -92,7 +90,6 @@ class PageTransition extends PageRouteBuilder { child: child, ), ); - break; case PageTransitionType.downToUp: return SlideTransition( transformHitTests: false, @@ -109,7 +106,6 @@ class PageTransition extends PageRouteBuilder { child: child, ), ); - break; case PageTransitionType.scale: return ScaleTransition( alignment: alignment, @@ -123,7 +119,6 @@ class PageTransition extends PageRouteBuilder { ), child: child, ); - break; case PageTransitionType.rotate: return RotationTransition( alignment: alignment, @@ -137,7 +132,6 @@ class PageTransition extends PageRouteBuilder { ), ), ); - break; case PageTransitionType.size: return Align( alignment: Alignment.center, @@ -149,7 +143,6 @@ class PageTransition extends PageRouteBuilder { child: child, ), ); - break; case PageTransitionType.rightToLeftWithFade: return SlideTransition( position: Tween( @@ -168,7 +161,6 @@ class PageTransition extends PageRouteBuilder { ), ), ); - break; case PageTransitionType.leftToRightWithFade: return SlideTransition( position: Tween( @@ -187,7 +179,6 @@ class PageTransition extends PageRouteBuilder { ), ), ); - break; default: return FadeTransition( opacity: animation, diff --git a/flutter_modular/lib/src/transitions/transitions.dart b/flutter_modular/lib/src/core/transitions/transitions.dart similarity index 99% rename from flutter_modular/lib/src/transitions/transitions.dart rename to flutter_modular/lib/src/core/transitions/transitions.dart index ad340684..1ee4c1cf 100644 --- a/flutter_modular/lib/src/transitions/transitions.dart +++ b/flutter_modular/lib/src/core/transitions/transitions.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; +import '../models/modular_arguments.dart'; -import '../../flutter_modular.dart'; import 'page_transition.dart'; PageRouteBuilder fadeInTransition( diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart new file mode 100644 index 00000000..b6f8d33a --- /dev/null +++ b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart @@ -0,0 +1,21 @@ +import '../../core/modules/child_module.dart'; +import 'modular_navigator_interface.dart'; + +abstract class ModularInterface { + bool get debugMode; + + String get initialRoute; + ChildModule get initialModule; + void init(ChildModule module); + void bindModule(ChildModule module, [String path]); + void debugPrintModular(String text); + + IModularNavigator get to; + IModularNavigator get link; + B? get({ + Map params = const {}, + List typesInRequest = const [], + B? defaultValue, + }); + void dispose(); +} diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart new file mode 100644 index 00000000..47a50d3f --- /dev/null +++ b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart @@ -0,0 +1,104 @@ +import 'package:flutter/widgets.dart'; + +abstract class IModularNavigator { + String get path; + String get modulePath; + + /// Navigate to a new screen. + /// + /// ``` + /// Modular.to.push(MaterialPageRoute(builder: (context) => HomePage()),); + /// ``` + Future push(Route route); + + /// Pop the current route off the navigator and navigate to a route. + /// + /// ``` + /// Modular.to.popAndPushNamed('/home'); + /// ``` + /// You could give parameters + /// ``` + /// Modular.to.popAndPushNamed('/home', arguments: 10); + /// ``` + Future popAndPushNamed( + String routeName, + {TO result, + Object arguments}); + + /// Navigate to a route. + /// + /// ``` + /// Modular.to.pushNamed('/home/10'); + /// ``` + /// You could give parameters + /// ``` + /// Modular.to.pushNamed('/home', arguments: 10); + /// ``` + Future pushNamed(String routeName, {Object arguments}); + + /// Push the route with the given name onto the navigator that most tightly + /// encloses the given context, and then remove all the previous routes until + /// the predicate returns true. + /// + /// ``` + /// Modular.to.pushNamedAndRemoveUntil('/home/10', ModalRoute.withName('/')); + /// ``` + /// You could give parameters + /// ``` + /// Modular.to.pushNamedAndRemoveUntil('/home', ModalRoute.withName('/'), arguments: 10); + /// ``` + Future pushNamedAndRemoveUntil( + String newRouteName, bool Function(Route) predicate, + {Object arguments}); + + ///Replace the current route of the navigator that most tightly encloses the + ///given context by pushing the route named routeName and then disposing the + ///previous route once the new route has finished animating in. + /// + /// ``` + /// Modular.to.pushReplacementNamed('/home/10'); + /// ``` + /// You could give parameters + /// ``` + /// Modular.to.pushReplacementNamed('/home', arguments: 10); + /// ``` + Future pushReplacementNamed( + String routeName, + {TO result, + Object arguments}); + + /// Removes the current Route from the stack of routes. + /// + /// ``` + /// Modular.to.pop(); + /// ``` + void pop([T result]); + + /// The initial route cannot be popped off the navigator, which implies that + /// this function returns true only if popping the navigator would not remove + /// the initial route. + /// + /// ``` + /// Modular.to.canPop(); + /// ``` + bool canPop(); + + ///Consults the current route's Route.willPop method, and acts accordingly, + ///potentially popping the route as a result; returns whether the pop request + ///should be considered handled. + /// + /// ``` + /// Modular.to.maybePop(); + /// ``` + Future maybePop([T result]); + + ///Calls pop repeatedly on the navigator that most tightly encloses the given + ///context until the predicate returns true. + /// + /// ``` + /// Modular.to.popUntil(ModalRoute.withName('/login')); + /// ``` + void popUntil(bool Function(Route) predicate); + + void navigate(String path, {dynamic arguments}); +} diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart new file mode 100644 index 00000000..ea1a60b6 --- /dev/null +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import '../core/modules/child_module.dart'; + +import 'interfaces/modular_interface.dart'; +import 'modular_impl.dart'; +import 'navigation/modular_route_information_parser.dart'; +import 'navigation/modular_router_delegate.dart'; + +final _navigatorKey = GlobalKey(); + +final Map _injectMap = {}; + +final _routeInformationParser = ModularRouteInformationParser(); +final _routerDelegate = ModularRouterDelegate( + _navigatorKey, + _routeInformationParser, + _injectMap, +); + +// ignore: non_constant_identifier_names +final ModularInterface Modular = ModularImpl( + routerDelegate: _routerDelegate, + injectMap: _injectMap, +); + +extension ModularExtension on MaterialApp { + MaterialApp modular() { + final app = MaterialApp.router( + key: key, + // scaffoldMessengerKey: scaffoldMessengerKey, + routeInformationProvider: routeInformationProvider, + backButtonDispatcher: backButtonDispatcher, + builder: builder, + title: title, + onGenerateTitle: onGenerateTitle, + color: color, + theme: theme, + darkTheme: darkTheme, + highContrastTheme: highContrastTheme, + highContrastDarkTheme: highContrastDarkTheme, + themeMode: themeMode, + locale: locale, + localizationsDelegates: localizationsDelegates, + localeListResolutionCallback: localeListResolutionCallback, + localeResolutionCallback: localeResolutionCallback, + supportedLocales: supportedLocales, + debugShowMaterialGrid: debugShowMaterialGrid, + showPerformanceOverlay: showPerformanceOverlay, + checkerboardRasterCacheImages: checkerboardRasterCacheImages, + checkerboardOffscreenLayers: checkerboardOffscreenLayers, + showSemanticsDebugger: showSemanticsDebugger, + debugShowCheckedModeBanner: debugShowCheckedModeBanner, + shortcuts: shortcuts, + actions: actions, + // restorationScopeId: restorationScopeId, + routeInformationParser: _routeInformationParser, + routerDelegate: _routerDelegate, + ); + + return app; + } +} diff --git a/flutter_modular/lib/src/presenters/modular_impl.dart b/flutter_modular/lib/src/presenters/modular_impl.dart new file mode 100644 index 00000000..0a3d6e2b --- /dev/null +++ b/flutter_modular/lib/src/presenters/modular_impl.dart @@ -0,0 +1,136 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_modular/src/core/errors/errors.dart'; +import 'package:flutter_modular/src/core/modules/child_module.dart'; + +import 'interfaces/modular_interface.dart'; +import 'interfaces/modular_navigator_interface.dart'; +import 'modular_base.dart'; +import 'navigation/modular_router_delegate.dart'; + +late ChildModule _initialModule; + +class ModularImpl implements ModularInterface { + final ModularRouterDelegate routerDelegate; + final Map injectMap; + IModularNavigator? navigatorDelegate; + + ModularImpl({ + required this.routerDelegate, + required this.injectMap, + this.navigatorDelegate, + }); + + @override + ChildModule get initialModule => _initialModule; + + @override + void debugPrintModular(String text) { + if (Modular.debugMode) { + debugPrint(text); + } + } + + @override + void bindModule(ChildModule module, [String path = '']) { + final name = module.runtimeType.toString(); + if (!injectMap.containsKey(name)) { + module.paths.add(path); + injectMap[name] = module; + module.instance(); + debugPrintModular("-- ${module.runtimeType.toString()} INITIALIZED"); + } else { + injectMap[name]?.paths.add(path); + } + } + + @override + void init(ChildModule module) { + _initialModule = module; + bindModule(module, "global=="); + } + + @override + IModularNavigator get to => navigatorDelegate ?? routerDelegate; + + @override + IModularNavigator get link => throw UnimplementedError(); + + @override + bool get debugMode => !kReleaseMode; + + @override + String get initialRoute => '/'; + + @override + B get( + {Map params = const {}, + List typesInRequest = const [], + B? defaultValue}) { + if (B.toString() == 'dynamic') { + throw ModularError('not allow for dynamic values'); + } + B? result; + + if (typesInRequest.isEmpty) { + final module = routerDelegate + .currentConfiguration?.currentModule.runtimeType + .toString() ?? + '=global'; + result = _getInjectableObject(module, + params: params, typesInRequest: typesInRequest); + } + + if (result != null) { + return result; + } + + for (var key in injectMap.keys) { + final value = _getInjectableObject(key, + params: params, typesInRequest: typesInRequest, checkKey: false); + if (value != null) { + return value; + } + } + + if (result == null && defaultValue != null) { + return defaultValue; + } + + throw ModularError('${B.toString()} not found'); + } + + B? _getInjectableObject( + String tag, { + Map params = const {}, + List typesInRequest = const [], + bool checkKey = true, + }) { + B? value; + if (!checkKey) { + value = injectMap[tag] + ?.getBind(params: params, typesInRequest: typesInRequest); + } else if (injectMap.containsKey(tag)) { + value = injectMap[tag] + ?.getBind(params: params, typesInRequest: typesInRequest); + } + + return value; + } + + @override + void dispose() { + if (B.toString() == 'dynamic') { + throw ModularError('not allow for dynamic values'); + } + + for (var key in injectMap.keys) { + if (_removeInjectableObject(key)) { + break; + } + } + } + + bool _removeInjectableObject(String tag) { + return injectMap[tag]?.remove() ?? false; + } +} diff --git a/flutter_modular/lib/src/presenters/navigation/modular_page.dart b/flutter_modular/lib/src/presenters/navigation/modular_page.dart new file mode 100644 index 00000000..3679236b --- /dev/null +++ b/flutter_modular/lib/src/presenters/navigation/modular_page.dart @@ -0,0 +1,78 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/core/errors/errors.dart'; +import '../../core/models/modular_router.dart'; + +final Map _allCompleters = {}; + +class ModularPage extends Page { + final ModularRouter router; + + ModularPage({LocalKey? key, required this.router}) + : super(key: key, name: router.path, arguments: router.args?.data); + + Future waitPop() { + if (_allCompleters.containsKey(hashCode)) { + return (_allCompleters[hashCode] as Completer).future; + } else { + _allCompleters[hashCode] = Completer(); + return (_allCompleters[hashCode] as Completer).future; + } + } + + void completePop(T result) { + if (_allCompleters.containsKey(hashCode) && + !(_allCompleters[hashCode] as Completer).isCompleted) { + (_allCompleters[hashCode] as Completer).complete(result); + _allCompleters.remove(hashCode); + } + } + + @override + Route createRoute(BuildContext context) { + if (router.transition == TransitionType.custom && + router.customTransition != null) { + return PageRouteBuilder( + pageBuilder: (context, _, __) { + if (router.child != null) { + return router.child!(context, router.args); + } else { + throw ModularError('Child not be null'); + } + }, + settings: this, + transitionsBuilder: router.customTransition!.transitionBuilder, + transitionDuration: router.customTransition!.transitionDuration, + ); + } else if (router.transition == TransitionType.defaultTransition) { + // Helper function + Widget widgetBuilder(BuildContext context) { + //return disposablePage; + return router.child!(context, router.args); + } + + if (router.routeGenerator != null) { + return router.routeGenerator!(widgetBuilder, this) as Route; + } + return MaterialPageRoute( + settings: this, + builder: widgetBuilder, + ); + } else { + var selectTransition = router.transitions[router.transition]; + if (selectTransition != null) { + return selectTransition( + router.child!, router.args, router.duration, this) as Route; + } else { + throw ModularError('Page Not Found'); + } + } + } +} + +class ModularRoute extends Route { + final ModularPage page; + + ModularRoute(this.page) : super(settings: page); +} diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart new file mode 100644 index 00000000..8261d445 --- /dev/null +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -0,0 +1,179 @@ +import 'package:flutter/material.dart'; +import '../../core/errors/errors.dart'; +import '../../core/models/modular_router.dart'; +import '../../core/modules/child_module.dart'; + +import '../modular_base.dart'; + +class ModularRouteInformationParser + extends RouteInformationParser { + @override + Future parseRouteInformation( + RouteInformation routeInformation) async { + final path = routeInformation.location ?? '/'; + final route = await selectRoute(path); + return route; + } + + @override + RouteInformation restoreRouteInformation(ModularRouter router) { + return RouteInformation(location: router.path); + } + + ModularRouter? _searchInModule( + ChildModule module, String routerName, String path) { + path = "/$path".replaceAll('//', '/'); + final routers = + module.routers.map((e) => e.copyWith(currentModule: module)).toList(); + routers.sort((preview, actual) { + return preview.routerName.contains('/:') ? 1 : 0; + }); + for (var route in routers) { + var r = _searchRoute(route, routerName, path); + if (r != null) { + return r; + } + } + return null; + } + + ModularRouter? _normalizeRoute( + ModularRouter route, String routerName, String path) { + ModularRouter? router; + if (routerName == path || routerName == "$path/") { + router = route.module!.routers[0]; + if (router.module != null) { + var _routerName = + (routerName + route.routerName).replaceFirst('//', '/'); + router = _searchInModule(route.module!, _routerName, path); + } + } else { + router = _searchInModule(route.module!, routerName, path); + } + return router; + } + + ModularRouter? _searchRoute( + ModularRouter route, String routerName, String path) { + final tempRouteName = + (routerName + route.routerName).replaceFirst('//', '/'); + if (route.child == null) { + var _routerName = + ('$routerName${route.routerName}/').replaceFirst('//', '/'); + var router = _normalizeRoute(route, _routerName, path); + + if (router != null) { + router = router.copyWith( + modulePath: router.modulePath == null ? '/' : tempRouteName, + path: path, + ); + + if (router.transition == TransitionType.defaultTransition) { + router = router.copyWith( + transition: route.transition, + customTransition: route.customTransition, + ); + } + if (route.module != null) { + Modular.bindModule(route.module!, path); + } + return router; + } + } else { + if (tempRouteName.split('/').length != path.split('/').length) { + return null; + } + var parseRoute = _parseUrlParams(route, tempRouteName, path); + + if (path != parseRoute.path) { + return null; + } + + if (parseRoute.currentModule != null) { + Modular.bindModule(parseRoute.currentModule!, path); + return parseRoute.copyWith(path: path); + } + } + + return null; + } + + String prepareToRegex(String url) { + final newUrl = []; + for (var part in url.split('/')) { + var url = part.contains(":") ? "(.*?)" : part; + newUrl.add(url); + } + + return newUrl.join("/"); + } + + ModularRouter _parseUrlParams( + ModularRouter router, String routeNamed, String path) { + if (routeNamed.contains('/:')) { + final regExp = RegExp( + "^${prepareToRegex(routeNamed)}\$", + caseSensitive: true, + ); + var r = regExp.firstMatch(path); + if (r != null) { + var params = {}; + var paramPos = 0; + final routeParts = routeNamed.split('/'); + final pathParts = path.split('/'); + + // print('Match! Processing $path as $routeNamed'); + + for (var routePart in routeParts) { + if (routePart.contains(":")) { + var paramName = routePart.replaceFirst(':', ''); + if (pathParts[paramPos].isNotEmpty) { + params[paramName] = pathParts[paramPos]; + routeNamed = + routeNamed.replaceFirst(routePart, params[paramName]!); + } + } + paramPos++; + } + + return router.copyWith( + args: router.args!.copyWith(params: params), path: routeNamed); + } + + return router.copyWith( + args: router.args!.copyWith(params: null), path: routeNamed); + } + + return router.copyWith(path: routeNamed); + } + + Future selectRoute(String path, [ChildModule? module]) async { + if (path.isEmpty) { + throw Exception("Router can not be empty"); + } + var route = _searchInModule(module ?? Modular.initialModule, "", path); + return canActivate(path, route); + } + + Future canActivate(String path, ModularRouter? router) async { + if (router == null) { + throw ModularError('Route not found'); + } + + if (router.guards?.isNotEmpty == true) { + for (var guard in router.guards!) { + try { + final result = await guard.canActivate(path, router); + if (!result) { + throw ModularError('$path is NOT ACTIVATE'); + } + // ignore: avoid_catches_without_on_clauses + } catch (e) { + throw ModularError( + 'RouteGuard error. Check ($path) in ${router.currentModule.runtimeType}'); + } + } + } + return router; + } +} diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart new file mode 100644 index 00000000..59d3e246 --- /dev/null +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -0,0 +1,184 @@ +import 'package:flutter/material.dart'; + +import '../../core/models/modular_router.dart'; +import '../../core/modules/child_module.dart'; +import '../interfaces/modular_navigator_interface.dart'; +import '../modular_base.dart'; +import 'modular_page.dart'; +import 'modular_route_information_parser.dart'; + +class ModularRouterDelegate extends RouterDelegate + with + // ignore: prefer_mixin + ChangeNotifier, + PopNavigatorRouterDelegateMixin + implements + IModularNavigator { + final GlobalKey navigatorKey; + final ModularRouteInformationParser parser; + final Map injectMap; + + ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); + + NavigatorState get navigator => navigatorKey.currentState!; + + ModularRouter? _router; + + List _pages = []; + + @override + ModularRouter? get currentConfiguration => _router; + ModularRouter get lastPage => _pages.last.router; + + @override + Widget build(BuildContext context) { + return _pages.isEmpty + ? Material() + : Navigator( + key: navigatorKey, + pages: _pages, + onPopPage: _onPopPage, + ); + } + + @override + Future setNewRoutePath(ModularRouter router) async { + final page = ModularPage( + key: ValueKey('url:${router.path}'), + router: router, + ); + if (_pages.isEmpty) { + _pages.add(page); + } else { + _pages.last.completePop(null); + _pages.last = page; + } + _router = router; + + rebuildPages(); + } + + @override + Future navigate(String path, {arguments}) async { + var router = await parser.selectRoute(path); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); + setNewRoutePath(router); + } + + bool _onPopPage(Route route, dynamic result) { + if (!route.didPop(result)) { + return false; + } + + if (route.isFirst) { + rebuildPages(); + return false; + } + + final page = route.settings as ModularPage; + final path = page.router.path; + page.completePop(result); + _pages.removeLast(); + rebuildPages(); + + final trash = []; + + injectMap.forEach((key, module) { + module.paths.remove(path); + if (module.paths.length == 0) { + module.cleanInjects(); + trash.add(key); + Modular.debugPrintModular( + "-- ${module.runtimeType.toString()} DISPOSED"); + } + }); + + for (final key in trash) { + injectMap.remove(key); + } + + return true; + } + + void rebuildPages() { + _pages = List.from(_pages); + notifyListeners(); + } + + @override + Future pushNamed(String routeName, + {Object? arguments}) async { + var router = await parser.selectRoute(routeName); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); + final page = ModularPage( + key: UniqueKey(), + router: router, + ); + _pages.add(page); + rebuildPages(); + return await page.waitPop(); + } + + @override + Future pushReplacementNamed( + String routeName, + {TO? result, + Object? arguments}) async { + var router = await parser.selectRoute(routeName); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); + final page = ModularPage( + key: UniqueKey(), + router: router, + ); + + _pages.last.completePop(result); + _pages.last = page; + rebuildPages(); + return await page.waitPop(); + } + + @override + Future popAndPushNamed( + String routeName, + {TO? result, + Object? arguments}) async { + _pages.last.completePop(result); + _pages.removeLast(); + return await pushNamed(routeName, arguments: arguments); + } + + @override + bool canPop() { + return navigator.canPop(); + } + + @override + Future maybePop([T? result]) => + navigator.maybePop(result); + + @override + void pop([T? result]) => navigator.pop(result); + + @override + void popUntil(bool Function(Route) predicate) => + navigator.popUntil(predicate); + + @override + Future pushNamedAndRemoveUntil( + String newRouteName, bool Function(Route) predicate, + {Object? arguments}) { + popUntil(predicate); + return pushNamed(newRouteName, arguments: arguments); + } + + @override + String get modulePath => _router!.modulePath ?? '/'; + + @override + String get path => _router!.path ?? '/'; + + @override + Future push(Route route) { + return navigator.push(route); + } +} diff --git a/flutter_modular/lib/src/presenters/widgets/modular_app.dart b/flutter_modular/lib/src/presenters/widgets/modular_app.dart new file mode 100644 index 00000000..81fe113d --- /dev/null +++ b/flutter_modular/lib/src/presenters/widgets/modular_app.dart @@ -0,0 +1,38 @@ +import 'package:flutter/widgets.dart'; +import '../../core/modules/main_module.dart'; + +import '../modular_base.dart'; + +class ModularApp extends StatefulWidget { + final MainModule module; + + ModularApp({ + Key? key, + required this.module, + }) : super(key: key); + + @override + _ModularAppState createState() => _ModularAppState(); +} + +class _ModularAppState extends State { + @override + void initState() { + super.initState(); + Modular.init(widget.module); + } + + @override + void dispose() { + widget.module.cleanInjects(); + if (Modular.debugMode) { + debugPrint("-- ${widget.module.runtimeType.toString()} DISPOSED"); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.module.bootstrap; + } +} diff --git a/flutter_modular/lib/src/presenters/widgets/modular_state.dart b/flutter_modular/lib/src/presenters/widgets/modular_state.dart new file mode 100644 index 00000000..1984cd47 --- /dev/null +++ b/flutter_modular/lib/src/presenters/widgets/modular_state.dart @@ -0,0 +1,14 @@ +import 'package:flutter/widgets.dart'; + +import '../modular_base.dart'; + +abstract class ModularState + extends State { + final TBind? controller = Modular.get(); + + @override + void dispose() { + super.dispose(); + Modular.dispose(); + } +} diff --git a/flutter_modular/lib/src/presenters/widgets/router_outlet.dart b/flutter_modular/lib/src/presenters/widgets/router_outlet.dart new file mode 100644 index 00000000..76d61bdb --- /dev/null +++ b/flutter_modular/lib/src/presenters/widgets/router_outlet.dart @@ -0,0 +1,70 @@ +import 'package:flutter/widgets.dart'; + +import 'widget_module.dart'; + +class RouterOutlet extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container(); + // return Router( + // routerDelegate: null, + // ); + } +} + +// class RouterOutlet extends StatefulWidget { +// final ChildModule module; +// final String initialRoute; +// final Key navigatorKey; +// final bool keepAlive; +// final void Function(String route) onChangeRoute; + +// RouterOutlet({ +// Key key, +// @required this.module, +// this.navigatorKey, +// this.initialRoute = '/', +// this.keepAlive = true, +// this.onChangeRoute, +// }) : super(key: key) { +// module.paths.add(runtimeType.toString()); +// } + +// @override +// _RouterOutletState createState() => _RouterOutletState(); +// } + +// class _RouterOutletState extends State +// with AutomaticKeepAliveClientMixin { +// GlobalKey _key; +// @override +// void initState() { +// super.initState(); +// // _key = widget.navigatorKey ?? +// // Modular.outletNavigatorKey(widget.module.runtimeType.toString()); +// } + +// @override +// Widget build(BuildContext context) { +// super.build(context); +// return WillPopScope( +// onWillPop: () async { +// return !await _key.currentState.maybePop(); +// }, +// child: ModularProvider( +// module: widget.module, +// child: Navigator( +// key: _key, +// initialRoute: widget.initialRoute, +// // onGenerateRoute: (setting) { +// // return Modular.generateRoute( +// // setting, widget.module, widget.onChangeRoute); +// // }, +// ), +// ), +// ); +// } + +// @override +// bool get wantKeepAlive => widget.keepAlive; +// } diff --git a/flutter_modular/lib/src/presenters/widgets/widget_module.dart b/flutter_modular/lib/src/presenters/widgets/widget_module.dart new file mode 100644 index 00000000..bd990aa7 --- /dev/null +++ b/flutter_modular/lib/src/presenters/widgets/widget_module.dart @@ -0,0 +1,109 @@ +import 'package:flutter/widgets.dart'; +import '../../core/inject/bind.dart'; +import '../../core/models/modular_router.dart'; +import '../../core/modules/child_module.dart'; + +import '../modular_base.dart'; + +_debugPrintModular(String text) { + if (Modular.debugMode) { + debugPrint(text); + } +} + +abstract class WidgetModule extends StatelessWidget implements ChildModule { + Widget get view; + + final _FakeModule _fakeModule = _FakeModule(); + + WidgetModule() { + _fakeModule.changeBinds(binds); + } + + @override + void changeBinds(List b) { + _fakeModule.changeBinds(b); + } + + @override + void cleanInjects() { + _fakeModule.cleanInjects(); + } + + @override + T? getBind( + {Map? params, List typesInRequest = const []}) { + return _fakeModule.getBind( + params: params, typesInRequest: typesInRequest); + } + + @override + List get paths => [runtimeType.toString()]; + + @override + bool remove() { + return _fakeModule.remove(); + } + + @override + void instance() { + _fakeModule.instance(); + } + + @override + List routers = const []; + + @override + Widget build(BuildContext context) { + return ModularProvider( + module: this, + child: view, + ); + } +} + +class _FakeModule extends ChildModule { + final List? bindsInject; + + _FakeModule({this.bindsInject}) { + paths.add(runtimeType.toString()); + } + + @override + List get binds => bindsInject ?? []; + + @override + List get routers => []; +} + +class ModularProvider extends StatefulWidget { + final ChildModule module; + final Widget child; + + const ModularProvider({Key? key, required this.module, required this.child}) + : super(key: key); + + @override + _ModularProviderState createState() => _ModularProviderState(); +} + +class _ModularProviderState extends State { + @override + void initState() { + super.initState(); + // Modular.addCoreInit(widget.module); + _debugPrintModular("-- ${widget.module.runtimeType} INITIALIZED"); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } + + @override + void dispose() { + super.dispose(); + // Modular.removeModule(widget.module); + _debugPrintModular("-- ${widget.module.runtimeType} DISPOSED"); + } +} diff --git a/flutter_modular/lib/src/test/modular_test_interface.dart b/flutter_modular/lib/src/test/modular_test_interface.dart index 7ce7ce46..0fb7067d 100644 --- a/flutter_modular/lib/src/test/modular_test_interface.dart +++ b/flutter_modular/lib/src/test/modular_test_interface.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; -import '../../flutter_modular.dart'; -import '../../flutter_modular_test.dart'; +import 'package:flutter_modular/src/core/inject/bind.dart'; +import 'package:flutter_modular/src/core/modules/child_module.dart'; +import 'package:flutter_modular/src/core/modules/main_module.dart'; + +import 'utils_test.dart'; enum ModularTestType { resetModules, keepModulesOnMemory } diff --git a/flutter_modular/lib/src/test/utils_test.dart b/flutter_modular/lib/src/test/utils_test.dart index 981eee22..b143bc6d 100644 --- a/flutter_modular/lib/src/test/utils_test.dart +++ b/flutter_modular/lib/src/test/utils_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; - -import '../../flutter_modular.dart'; +import 'package:flutter_modular/src/core/inject/bind.dart'; +import 'package:flutter_modular/src/core/modules/child_module.dart'; void initModule(ChildModule module, {List changeBinds = const [], bool initialModule = false}) { diff --git a/flutter_modular/test/src/core/errors/errors_test.dart b/flutter_modular/test/src/core/errors/errors_test.dart new file mode 100644 index 00000000..cc3d9505 --- /dev/null +++ b/flutter_modular/test/src/core/errors/errors_test.dart @@ -0,0 +1,8 @@ +import 'package:flutter_modular/src/core/errors/errors.dart'; +import 'package:flutter_test/flutter_test.dart'; + +main() { + test('to string', () { + expect(ModularError('message').toString(), 'ModularError: message'); + }); +} diff --git a/flutter_modular/test/src/core/inject/bind_test.dart b/flutter_modular/test/src/core/inject/bind_test.dart new file mode 100644 index 00000000..4e6d8f32 --- /dev/null +++ b/flutter_modular/test/src/core/inject/bind_test.dart @@ -0,0 +1,17 @@ +import 'package:flutter_modular/src/core/inject/bind.dart'; +import 'package:flutter_test/flutter_test.dart'; + +main() { + test('singleton can\'t be false if \'lazy\' is also false', () { + expect(() => Bind((i) => String, lazy: false, singleton: false), + throwsAssertionError); + }); + + test('factories', () { + expect(Bind.instance('string'), isA>()); + expect(Bind.factory((i) => 'string'), isA>()); + expect(Bind.lazySingleton((i) => 'string'), isA>()); + expect(Bind.singleton((i) => 'string'), isA>()); + expect(BindInject((i) => 'string'), isA>()); + }); +} diff --git a/flutter_modular/test/src/core/models/modular_arguments_test.dart b/flutter_modular/test/src/core/models/modular_arguments_test.dart new file mode 100644 index 00000000..a0ac102c --- /dev/null +++ b/flutter_modular/test/src/core/models/modular_arguments_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_modular/src/core/models/modular_arguments.dart'; +import 'package:flutter_test/flutter_test.dart'; + +main() { + test('should make copy with implementation', () { + final model = ModularArguments.empty(); + final copy = model.copyWith(); + expect(model != copy, true); + }); +} diff --git a/flutter_modular/test/src/core/models/modular_router_test.dart b/flutter_modular/test/src/core/models/modular_router_test.dart new file mode 100644 index 00000000..c2537e21 --- /dev/null +++ b/flutter_modular/test/src/core/models/modular_router_test.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/core/models/modular_router.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../modules/child_module_test.dart'; + +main() { + test('should initializa in incorrect form', () { + expect( + () => ModularRouter('/', + child: (context, args) => Container(), module: ModuleMock()), + throwsAssertionError); + + expect( + () => ModularRouter('/', + transition: TransitionType.custom, module: ModuleMock()), + throwsAssertionError); + + expect( + () => ModularRouter('/', + children: [ModularRouter('/')], module: ModuleMock()), + throwsAssertionError); + }); + + test('should make copy with implementation', () { + final model = ModularRouter('/', module: ModuleMock()); + final copy = model.copyWith(); + expect(copy.module, isA()); + final copy2 = model.copyWith(path: '/home'); + expect(copy2.module, isA()); + expect(copy2.path, '/home'); + expect(copy.hashCode, equals(copy2.hashCode)); + expect(copy == copy2, true); + }); + + test('should normal instance custom transition', () { + final model = ModularRouter('/', + transition: TransitionType.custom, module: ModuleMock(), + customTransition: CustomTransition(transitionBuilder: (c, a1, a2, w) { + return FadeTransition( + opacity: a1, + ); + })); + expect(model.transition, TransitionType.custom); + }); +} diff --git a/flutter_modular/test/src/core/modules/child_module_test.dart b/flutter_modular/test/src/core/modules/child_module_test.dart new file mode 100644 index 00000000..75cb0b64 --- /dev/null +++ b/flutter_modular/test/src/core/modules/child_module_test.dart @@ -0,0 +1,116 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/core/errors/errors.dart'; +import 'package:flutter_modular/src/core/inject/bind.dart'; +import 'package:flutter_modular/src/core/models/modular_router.dart'; +import 'package:flutter_modular/src/core/modules/child_module.dart'; +import 'package:flutter_test/flutter_test.dart'; + +class ModuleMock extends ChildModule { + @override + List binds = [ + Bind((i) => "Test"), + Bind((i) => true, lazy: false), + Bind((i) => StreamController(), lazy: false), + Bind((i) => ValueNotifier(0), lazy: false), + ]; + + @override + List routers = []; +} + +main() { + var module = ModuleMock(); + + setUp(() { + module = ModuleMock(); + }); + + test('should return the same objects in list of binds', () { + final list1 = module.binds; + final list2 = module.binds; + expect(list1, equals(list2)); + }); + + test('should change binds into new list of bind', () { + module.changeBinds([ + Bind((i) => "Test"), + Bind((i) => true), + Bind((i) => 0.0), + ]); + expect(module.binds.length, 3); + }); + + test('should get bind', () { + expect(module.getBind(typesInRequest: []), equals('Test')); + expect(module.getBind(typesInRequest: []), equals(true)); + expect(module.getBind(typesInRequest: []), equals(true)); + }); + + test('should return null if not found bind', () { + expect(module.getBind(typesInRequest: []), null); + }); + + test('should throw exception when exist value over in the injection search', + () { + expect(() => module.getBind(typesInRequest: [bool]), + throwsA(isA())); + }); + + test('should Create a instance of all binds isn\'t lazy Loaded', () { + module.instance(); + expect(module.getBind(typesInRequest: [bool]), equals(true)); + }); + + test('should remove bind', () { + module.instance(); + expect(module.getBind(typesInRequest: [bool]), equals(true)); + + module.remove(); + expect(() => module.getBind(typesInRequest: [bool]), + throwsA(isA())); + + //Stream + expect(module.getBind(typesInRequest: [StreamController]), + isA()); + + module.remove(); + expect( + () => module + .getBind(typesInRequest: [StreamController]), + throwsA(isA())); + + //ChangeNotifier + expect(module.getBind(typesInRequest: [ChangeNotifier]), + isA()); + + module.remove(); + expect( + () => module.getBind(typesInRequest: [ChangeNotifier]), + throwsA(isA())); + }); + + test('should clean all injections', () { + module.instance(); + expect(module.getBind(typesInRequest: [bool]), equals(true)); + expect(module.getBind(typesInRequest: [StreamController]), + isA()); + expect(module.getBind(typesInRequest: [ChangeNotifier]), + isA()); + + module.cleanInjects(); + + expect(() => module.getBind(typesInRequest: [bool]), + throwsA(isA())); + + expect( + () => module + .getBind(typesInRequest: [StreamController]), + throwsA(isA())); + + expect( + () => module.getBind(typesInRequest: [ChangeNotifier]), + throwsA(isA())); + }); +} diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart new file mode 100644 index 00000000..03273142 --- /dev/null +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -0,0 +1,133 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_modular/flutter_modular.dart'; +import 'package:flutter_modular/src/presenters/navigation/modular_route_information_parser.dart'; +import 'package:flutter_test/flutter_test.dart'; + +main() { + var parse = ModularRouteInformationParser(); + + BuildContext context = Container().createElement(); + + group('Single Module | ', () { + test('should retrive router /', () async { + final route = await parse.selectRoute('/', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + }); + + test('should retrive router /list', () async { + final route = await parse.selectRoute('/list', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + }); + test('should retrive dynamic router /list/:id', () async { + final route = await parse.selectRoute('/list/2', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, route.args).toString(), '2'); + }); + }); + + group('Multi Module | ', () { + test('should retrive router /mock', () async { + final route = await parse.selectRoute('/mock', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + }); + + test('should retrive router /mock/', () async { + final route = await parse.selectRoute('/mock/', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + }); + + test('should retrive router /mock/list', () async { + final route = await parse.selectRoute('/mock/list', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + }); + + test('should retrive dynamic router /mock/list/:id', () async { + final route = await parse.selectRoute('/mock/list/3', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, route.args).toString(), '3'); + }); + }); +} + +class ModuleMock extends ChildModule { + @override + List binds = [ + Bind((i) => "Test"), + Bind((i) => true, lazy: false), + Bind((i) => StreamController(), lazy: false), + Bind((i) => ValueNotifier(0), lazy: false), + ]; + + @override + List routers = [ + ModularRouter( + '/', + child: (context, args) => Container(), + ), + ModularRouter( + '/mock', + module: ModuleMock2(), + ), + ModularRouter( + '/list', + child: (context, args) => ListView(), + ), + ModularRouter( + '/list/:id', + child: (context, args) => CustomWidget( + text: args?.params!['id'], + ), + ), + ]; +} + +class ModuleMock2 extends ChildModule { + @override + List binds = [ + Bind((i) => "Test"), + Bind((i) => true, lazy: false), + Bind((i) => StreamController(), lazy: false), + Bind((i) => ValueNotifier(0), lazy: false), + ]; + + @override + List routers = [ + ModularRouter( + '/', + child: (context, args) => SizedBox(), + ), + ModularRouter( + '/list', + child: (context, args) => ListView(), + ), + ModularRouter( + '/list/:id', + child: (context, args) => CustomWidget( + text: args?.params!['id'], + ), + ), + ]; +} + +class CustomWidget extends StatelessWidget { + final String text; + + const CustomWidget({Key? key, required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container(); + } + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return text; + } +} From b8bb2176e540ebfc8d9858a615eb2bca96b9417b Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 1 Dec 2020 18:23:31 -0300 Subject: [PATCH 31/71] router outlet --- flutter_modular/lib/flutter_modular.dart | 2 +- .../route_outlet_information_parser.dart | 179 +++++++++++++++++ .../router_outlet.dart | 33 +++- .../router_outlet/router_outlet_delegate.dart | 184 ++++++++++++++++++ 4 files changed, 392 insertions(+), 6 deletions(-) create mode 100644 flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart rename flutter_modular/lib/src/presenters/{widgets => router_outlet}/router_outlet.dart (69%) create mode 100644 flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 559f07ef..c0a8fd88 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -10,7 +10,7 @@ export 'src/core/models/modular_router.dart'; export 'src/core/modules/child_module.dart'; export 'src/core/modules/main_module.dart'; export 'src/presenters/modular_base.dart'; +export 'src/presenters/router_outlet/router_outlet.dart'; export 'src/presenters/widgets/modular_app.dart'; export 'src/presenters/widgets/modular_state.dart'; -export 'src/presenters/widgets/router_outlet.dart'; export 'src/presenters/widgets/widget_module.dart'; diff --git a/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart b/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart new file mode 100644 index 00000000..e79a3208 --- /dev/null +++ b/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart @@ -0,0 +1,179 @@ +import 'package:flutter/material.dart'; +import '../../core/errors/errors.dart'; +import '../../core/models/modular_router.dart'; +import '../../core/modules/child_module.dart'; + +import '../modular_base.dart'; + +class RouterOutletInformationParser + extends RouteInformationParser { + @override + Future parseRouteInformation( + RouteInformation routeInformation) async { + final path = routeInformation.location ?? '/'; + final route = await selectRoute(path); + return route; + } + + @override + RouteInformation restoreRouteInformation(ModularRouter router) { + return RouteInformation(location: router.path); + } + + ModularRouter? _searchInModule( + ChildModule module, String routerName, String path) { + path = "/$path".replaceAll('//', '/'); + final routers = + module.routers.map((e) => e.copyWith(currentModule: module)).toList(); + routers.sort((preview, actual) { + return preview.routerName.contains('/:') ? 1 : 0; + }); + for (var route in routers) { + var r = _searchRoute(route, routerName, path); + if (r != null) { + return r; + } + } + return null; + } + + ModularRouter? _normalizeRoute( + ModularRouter route, String routerName, String path) { + ModularRouter? router; + if (routerName == path || routerName == "$path/") { + router = route.module!.routers[0]; + if (router.module != null) { + var _routerName = + (routerName + route.routerName).replaceFirst('//', '/'); + router = _searchInModule(route.module!, _routerName, path); + } + } else { + router = _searchInModule(route.module!, routerName, path); + } + return router; + } + + ModularRouter? _searchRoute( + ModularRouter route, String routerName, String path) { + final tempRouteName = + (routerName + route.routerName).replaceFirst('//', '/'); + if (route.child == null) { + var _routerName = + ('$routerName${route.routerName}/').replaceFirst('//', '/'); + var router = _normalizeRoute(route, _routerName, path); + + if (router != null) { + router = router.copyWith( + modulePath: router.modulePath == null ? '/' : tempRouteName, + path: path, + ); + + if (router.transition == TransitionType.defaultTransition) { + router = router.copyWith( + transition: route.transition, + customTransition: route.customTransition, + ); + } + if (route.module != null) { + Modular.bindModule(route.module!, path); + } + return router; + } + } else { + if (tempRouteName.split('/').length != path.split('/').length) { + return null; + } + var parseRoute = _parseUrlParams(route, tempRouteName, path); + + if (path != parseRoute.path) { + return null; + } + + if (parseRoute.currentModule != null) { + Modular.bindModule(parseRoute.currentModule!, path); + return parseRoute.copyWith(path: path); + } + } + + return null; + } + + String prepareToRegex(String url) { + final newUrl = []; + for (var part in url.split('/')) { + var url = part.contains(":") ? "(.*?)" : part; + newUrl.add(url); + } + + return newUrl.join("/"); + } + + ModularRouter _parseUrlParams( + ModularRouter router, String routeNamed, String path) { + if (routeNamed.contains('/:')) { + final regExp = RegExp( + "^${prepareToRegex(routeNamed)}\$", + caseSensitive: true, + ); + var r = regExp.firstMatch(path); + if (r != null) { + var params = {}; + var paramPos = 0; + final routeParts = routeNamed.split('/'); + final pathParts = path.split('/'); + + // print('Match! Processing $path as $routeNamed'); + + for (var routePart in routeParts) { + if (routePart.contains(":")) { + var paramName = routePart.replaceFirst(':', ''); + if (pathParts[paramPos].isNotEmpty) { + params[paramName] = pathParts[paramPos]; + routeNamed = + routeNamed.replaceFirst(routePart, params[paramName]!); + } + } + paramPos++; + } + + return router.copyWith( + args: router.args!.copyWith(params: params), path: routeNamed); + } + + return router.copyWith( + args: router.args!.copyWith(params: null), path: routeNamed); + } + + return router.copyWith(path: routeNamed); + } + + Future selectRoute(String path, [ChildModule? module]) async { + if (path.isEmpty) { + throw Exception("Router can not be empty"); + } + var route = _searchInModule(module ?? Modular.initialModule, "", path); + return canActivate(path, route); + } + + Future canActivate(String path, ModularRouter? router) async { + if (router == null) { + throw ModularError('Route not found'); + } + + if (router.guards?.isNotEmpty == true) { + for (var guard in router.guards!) { + try { + final result = await guard.canActivate(path, router); + if (!result) { + throw ModularError('$path is NOT ACTIVATE'); + } + // ignore: avoid_catches_without_on_clauses + } catch (e) { + throw ModularError( + 'RouteGuard error. Check ($path) in ${router.currentModule.runtimeType}'); + } + } + } + return router; + } +} diff --git a/flutter_modular/lib/src/presenters/widgets/router_outlet.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart similarity index 69% rename from flutter_modular/lib/src/presenters/widgets/router_outlet.dart rename to flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart index 76d61bdb..ca92dbfc 100644 --- a/flutter_modular/lib/src/presenters/widgets/router_outlet.dart +++ b/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart @@ -1,15 +1,38 @@ import 'package:flutter/widgets.dart'; -import 'widget_module.dart'; +import 'route_outlet_information_parser.dart'; +import 'router_outlet_delegate.dart'; class RouterOutlet extends StatelessWidget { + final navigatorKey = GlobalKey(); + final parser = RouterOutletInformationParser(); + final provider = Providerd(); + late final delegate = RouterOutletDelegate(navigatorKey, parser, {}); + @override Widget build(BuildContext context) { - return Container(); - // return Router( - // routerDelegate: null, - // ); + return Router( + routeInformationParser: parser, + routeInformationProvider: provider, + routerDelegate: delegate, + ); + } +} + +class Providerd extends RouteInformationProvider { + @override + void addListener(listener) { + // TODO: implement addListener } + + @override + void removeListener(listener) { + // TODO: implement removeListener + } + + @override + // TODO: implement value + RouteInformation? get value => RouteInformation(location: '/home'); } // class RouterOutlet extends StatefulWidget { diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart new file mode 100644 index 00000000..2c953491 --- /dev/null +++ b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart @@ -0,0 +1,184 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/presenters/navigation/modular_page.dart'; + +import '../../core/models/modular_router.dart'; +import '../../core/modules/child_module.dart'; +import '../interfaces/modular_navigator_interface.dart'; +import '../modular_base.dart'; +import 'route_outlet_information_parser.dart'; + +class RouterOutletDelegate extends RouterDelegate + with + // ignore: prefer_mixin + ChangeNotifier, + PopNavigatorRouterDelegateMixin + implements + IModularNavigator { + final GlobalKey navigatorKey; + final RouterOutletInformationParser parser; + final Map injectMap; + + RouterOutletDelegate(this.navigatorKey, this.parser, this.injectMap); + + NavigatorState get navigator => navigatorKey.currentState!; + + ModularRouter? _router; + + List _pages = []; + + @override + ModularRouter? get currentConfiguration => _router; + ModularRouter get lastPage => _pages.last.router; + + @override + Widget build(BuildContext context) { + return _pages.isEmpty + ? Material() + : Navigator( + key: navigatorKey, + pages: _pages, + onPopPage: _onPopPage, + ); + } + + @override + Future setNewRoutePath(ModularRouter router) async { + final page = ModularPage( + key: ValueKey('url:${router.path}'), + router: router, + ); + if (_pages.isEmpty) { + _pages.add(page); + } else { + _pages.last.completePop(null); + _pages.last = page; + } + _router = router; + + rebuildPages(); + } + + @override + Future navigate(String path, {arguments}) async { + var router = await parser.selectRoute(path); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); + setNewRoutePath(router); + } + + bool _onPopPage(Route route, dynamic result) { + if (!route.didPop(result)) { + return false; + } + + if (route.isFirst) { + rebuildPages(); + return false; + } + + final page = route.settings as ModularPage; + final path = page.router.path; + page.completePop(result); + _pages.removeLast(); + rebuildPages(); + + final trash = []; + + injectMap.forEach((key, module) { + module.paths.remove(path); + if (module.paths.length == 0) { + module.cleanInjects(); + trash.add(key); + Modular.debugPrintModular( + "-- ${module.runtimeType.toString()} DISPOSED"); + } + }); + + for (final key in trash) { + injectMap.remove(key); + } + + return true; + } + + void rebuildPages() { + _pages = List.from(_pages); + notifyListeners(); + } + + @override + Future pushNamed(String routeName, + {Object? arguments}) async { + var router = await parser.selectRoute(routeName); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); + final page = ModularPage( + key: UniqueKey(), + router: router, + ); + _pages.add(page); + rebuildPages(); + return await page.waitPop(); + } + + @override + Future pushReplacementNamed( + String routeName, + {TO? result, + Object? arguments}) async { + var router = await parser.selectRoute(routeName); + router = router.copyWith(args: router.args?.copyWith(data: arguments)); + final page = ModularPage( + key: UniqueKey(), + router: router, + ); + + _pages.last.completePop(result); + _pages.last = page; + rebuildPages(); + return await page.waitPop(); + } + + @override + Future popAndPushNamed( + String routeName, + {TO? result, + Object? arguments}) async { + _pages.last.completePop(result); + _pages.removeLast(); + return await pushNamed(routeName, arguments: arguments); + } + + @override + bool canPop() { + return navigator.canPop(); + } + + @override + Future maybePop([T? result]) => + navigator.maybePop(result); + + @override + void pop([T? result]) => navigator.pop(result); + + @override + void popUntil(bool Function(Route) predicate) => + navigator.popUntil(predicate); + + @override + Future pushNamedAndRemoveUntil( + String newRouteName, bool Function(Route) predicate, + {Object? arguments}) { + popUntil(predicate); + return pushNamed(newRouteName, arguments: arguments); + } + + @override + String get modulePath => _router!.modulePath ?? '/'; + + @override + String get path => _router!.path ?? '/'; + + @override + Future push(Route route) { + return navigator.push(route); + } +} From 7dce2a90fd28f46ef2ded22f10a4d1606e1d2c03 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 4 Dec 2020 16:52:47 -0300 Subject: [PATCH 32/71] router outlet implements --- flutter_modular/lib/flutter_modular.dart | 2 +- .../lib/src/core/models/modular_router.dart | 5 + .../modular_navigator_interface.dart | 17 +- .../lib/src/presenters/modular_base.dart | 15 ++ .../modular_route_information_parser.dart | 33 +++- .../navigation/modular_router_delegate.dart | 46 +++-- .../route_outlet_information_parser.dart | 3 +- .../router_outlet/router_outlet.dart | 44 +++-- .../router_outlet/router_outlet_delegate.dart | 176 ++---------------- .../widgets/navigation_listener.dart | 37 ++++ flutter_modular/pubspec.yaml | 2 +- flutter_modular/rocket.drawio | 13 ++ .../modular_route_information_parse_test.dart | 54 ++++++ 13 files changed, 243 insertions(+), 204 deletions(-) create mode 100644 flutter_modular/lib/src/presenters/widgets/navigation_listener.dart create mode 100644 flutter_modular/rocket.drawio diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index c0a8fd88..e9798a52 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -10,7 +10,7 @@ export 'src/core/models/modular_router.dart'; export 'src/core/modules/child_module.dart'; export 'src/core/modules/main_module.dart'; export 'src/presenters/modular_base.dart'; -export 'src/presenters/router_outlet/router_outlet.dart'; export 'src/presenters/widgets/modular_app.dart'; export 'src/presenters/widgets/modular_state.dart'; +export 'src/presenters/widgets/navigation_listener.dart'; export 'src/presenters/widgets/widget_module.dart'; diff --git a/flutter_modular/lib/src/core/models/modular_router.dart b/flutter_modular/lib/src/core/models/modular_router.dart index c24d2702..50264da8 100644 --- a/flutter_modular/lib/src/core/models/modular_router.dart +++ b/flutter_modular/lib/src/core/models/modular_router.dart @@ -20,6 +20,8 @@ class ModularRouter { final List children; + final List routerOutlet; + final String? path; /// @@ -197,6 +199,7 @@ class ModularRouter { this.module, this.child, this.guards, + this.routerOutlet = const [], this.params, this.currentModule, this.transition = TransitionType.defaultTransition, @@ -217,6 +220,7 @@ class ModularRouter { String? routerName, ChildModule? module, List? children, + List? routerOutlet, ChildModule? currentModule, Map? params, List? guards, @@ -234,6 +238,7 @@ class ModularRouter { args: args ?? this.args, children: children ?? this.children, module: module ?? this.module, + routerOutlet: routerOutlet ?? this.routerOutlet, currentModule: currentModule ?? this.currentModule, params: params ?? this.params, modulePath: modulePath ?? this.modulePath, diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart index 47a50d3f..bb91d7fe 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart @@ -2,8 +2,12 @@ import 'package:flutter/widgets.dart'; abstract class IModularNavigator { String get path; + String get localPath; String get modulePath; + void addListener(void Function() listener); + void removeListener(void Function() listener); + /// Navigate to a new screen. /// /// ``` @@ -23,7 +27,8 @@ abstract class IModularNavigator { Future popAndPushNamed( String routeName, {TO result, - Object arguments}); + Object arguments, + bool linked = false}); /// Navigate to a route. /// @@ -34,7 +39,8 @@ abstract class IModularNavigator { /// ``` /// Modular.to.pushNamed('/home', arguments: 10); /// ``` - Future pushNamed(String routeName, {Object arguments}); + Future pushNamed(String routeName, + {Object arguments, bool linked = false}); /// Push the route with the given name onto the navigator that most tightly /// encloses the given context, and then remove all the previous routes until @@ -49,7 +55,7 @@ abstract class IModularNavigator { /// ``` Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, - {Object arguments}); + {Object arguments, bool linked = false}); ///Replace the current route of the navigator that most tightly encloses the ///given context by pushing the route named routeName and then disposing the @@ -65,7 +71,8 @@ abstract class IModularNavigator { Future pushReplacementNamed( String routeName, {TO result, - Object arguments}); + Object arguments, + bool linked = false}); /// Removes the current Route from the stack of routes. /// @@ -100,5 +107,5 @@ abstract class IModularNavigator { /// ``` void popUntil(bool Function(Route) predicate); - void navigate(String path, {dynamic arguments}); + void navigate(String path, {dynamic arguments, bool linked = false}); } diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index ea1a60b6..e13c6090 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -1,10 +1,13 @@ import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/presenters/router_outlet/route_outlet_information_parser.dart'; +import 'package:flutter_modular/src/presenters/router_outlet/router_outlet_delegate.dart'; import '../core/modules/child_module.dart'; import 'interfaces/modular_interface.dart'; import 'modular_impl.dart'; import 'navigation/modular_route_information_parser.dart'; import 'navigation/modular_router_delegate.dart'; +import 'router_outlet/router_outlet.dart'; final _navigatorKey = GlobalKey(); @@ -60,3 +63,15 @@ extension ModularExtension on MaterialApp { return app; } } + +class RouterOutlet extends StatelessWidget { + final navigatorKey = GlobalKey(); + late final delegate = RouterOutletDelegate(_routerDelegate); + + @override + Widget build(BuildContext context) { + return Router( + routerDelegate: delegate, + ); + } +} diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 8261d445..d48086fc 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -10,6 +10,7 @@ class ModularRouteInformationParser @override Future parseRouteInformation( RouteInformation routeInformation) async { + print(routeInformation); final path = routeInformation.location ?? '/'; final route = await selectRoute(path); return route; @@ -17,7 +18,11 @@ class ModularRouteInformationParser @override RouteInformation restoreRouteInformation(ModularRouter router) { - return RouteInformation(location: router.path); + return RouteInformation( + location: router.routerOutlet.isEmpty + ? router.path + : router.routerOutlet.last.path, + ); } ModularRouter? _searchInModule( @@ -80,6 +85,20 @@ class ModularRouteInformationParser return router; } } else { + if (route.children.isNotEmpty) { + for (var routeChild in route.children) { + var r = _searchRoute(routeChild, route.routerName, path); + if (r != null) { + route = route.copyWith(routerOutlet: [ + r.copyWith( + modulePath: resolveOutletModulePath( + tempRouteName, r.modulePath ?? '/')) + ], path: tempRouteName); + return route; + } + } + } + if (tempRouteName.split('/').length != path.split('/').length) { return null; } @@ -91,13 +110,23 @@ class ModularRouteInformationParser if (parseRoute.currentModule != null) { Modular.bindModule(parseRoute.currentModule!, path); - return parseRoute.copyWith(path: path); } + return parseRoute.copyWith(path: path); } return null; } + String resolveOutletModulePath( + String tempRouteName, String outletModulePath) { + var temp = '$tempRouteName/$outletModulePath'.replaceAll('//', '/'); + if (temp.characters.last == '/') { + return temp.substring(0, temp.length - 1); + } else { + return temp; + } + } + String prepareToRegex(String url) { final newUrl = []; for (var part in url.split('/')) { diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index 59d3e246..ebc1f1c0 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -22,13 +22,10 @@ class ModularRouterDelegate extends RouterDelegate NavigatorState get navigator => navigatorKey.currentState!; - ModularRouter? _router; - List _pages = []; @override - ModularRouter? get currentConfiguration => _router; - ModularRouter get lastPage => _pages.last.router; + ModularRouter? get currentConfiguration => _pages.last.router; @override Widget build(BuildContext context) { @@ -43,6 +40,8 @@ class ModularRouterDelegate extends RouterDelegate @override Future setNewRoutePath(ModularRouter router) async { + print('setNewRoutePath: ${router.routerOutlet.length}'); + final page = ModularPage( key: ValueKey('url:${router.path}'), router: router, @@ -53,14 +52,16 @@ class ModularRouterDelegate extends RouterDelegate _pages.last.completePop(null); _pages.last = page; } - _router = router; rebuildPages(); } @override - Future navigate(String path, {arguments}) async { - var router = await parser.selectRoute(path); + Future navigate(String routeName, + {arguments, bool linked = false}) async { + print('navigate: $routeName'); + var router = + await parser.selectRoute(linked ? modulePath + routeName : routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); setNewRoutePath(router); } @@ -107,8 +108,9 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamed(String routeName, - {Object? arguments}) async { - var router = await parser.selectRoute(routeName); + {Object? arguments, bool linked = false}) async { + var router = + await parser.selectRoute(linked ? modulePath + routeName : routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); final page = ModularPage( key: UniqueKey(), @@ -123,8 +125,10 @@ class ModularRouterDelegate extends RouterDelegate Future pushReplacementNamed( String routeName, {TO? result, - Object? arguments}) async { - var router = await parser.selectRoute(routeName); + Object? arguments, + bool linked = false}) async { + var router = + await parser.selectRoute(linked ? modulePath + routeName : routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); final page = ModularPage( key: UniqueKey(), @@ -141,10 +145,11 @@ class ModularRouterDelegate extends RouterDelegate Future popAndPushNamed( String routeName, {TO? result, - Object? arguments}) async { + Object? arguments, + bool linked = false}) async { _pages.last.completePop(result); _pages.removeLast(); - return await pushNamed(routeName, arguments: arguments); + return await pushNamed(routeName, arguments: arguments, linked: linked); } @override @@ -166,16 +171,23 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, - {Object? arguments}) { + {Object? arguments, bool linked = false}) { popUntil(predicate); - return pushNamed(newRouteName, arguments: arguments); + return pushNamed(newRouteName, arguments: arguments, linked: linked); } @override - String get modulePath => _router!.modulePath ?? '/'; + String get modulePath => currentConfiguration?.routerOutlet.isEmpty == true + ? currentConfiguration?.modulePath ?? '/' + : currentConfiguration?.routerOutlet.last.modulePath ?? '/'; + + @override + String get path => currentConfiguration?.routerOutlet.isEmpty == true + ? currentConfiguration?.path ?? '/' + : currentConfiguration?.routerOutlet.last.path ?? '/'; @override - String get path => _router!.path ?? '/'; + String get localPath => path.replaceFirst(modulePath, ''); @override Future push(Route route) { diff --git a/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart b/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart index e79a3208..87b5eafb 100644 --- a/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart +++ b/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart @@ -83,6 +83,7 @@ class RouterOutletInformationParser if (tempRouteName.split('/').length != path.split('/').length) { return null; } + var parseRoute = _parseUrlParams(route, tempRouteName, path); if (path != parseRoute.path) { @@ -91,7 +92,7 @@ class RouterOutletInformationParser if (parseRoute.currentModule != null) { Modular.bindModule(parseRoute.currentModule!, path); - return parseRoute.copyWith(path: path); + return parseRoute; } } diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart index ca92dbfc..91aa32aa 100644 --- a/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart +++ b/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart @@ -1,38 +1,46 @@ import 'package:flutter/widgets.dart'; +import 'package:flutter_modular/src/core/models/modular_router.dart'; +import 'package:flutter_modular/src/presenters/modular_base.dart'; +import 'package:flutter_modular/src/presenters/navigation/modular_router_delegate.dart'; + import 'route_outlet_information_parser.dart'; import 'router_outlet_delegate.dart'; -class RouterOutlet extends StatelessWidget { - final navigatorKey = GlobalKey(); - final parser = RouterOutletInformationParser(); - final provider = Providerd(); - late final delegate = RouterOutletDelegate(navigatorKey, parser, {}); +// class RouterOutlet extends StatelessWidget { +// final navigatorKey = GlobalKey(); +// final parser = RouterOutletInformationParser(); +// final provider = Providerd(); +// late final delegate = RouterOutletDelegate(navigatorKey, parser, {}); - @override - Widget build(BuildContext context) { - return Router( - routeInformationParser: parser, - routeInformationProvider: provider, - routerDelegate: delegate, - ); - } -} +// @override +// Widget build(BuildContext context) { + +// return Router( +// routeInformationProvider: provider, +// routeInformationParser: parser, +// routerDelegate: delegate, +// ); +// } +// } class Providerd extends RouteInformationProvider { + final ModularRouterDelegate _delegate; + Providerd(this._delegate); + @override void addListener(listener) { - // TODO: implement addListener + print(listener); + print(Modular.to.path); } @override void removeListener(listener) { - // TODO: implement removeListener + print('removeListener'); } @override - // TODO: implement value - RouteInformation? get value => RouteInformation(location: '/home'); + RouteInformation? get value => RouteInformation(location: '/other'); } // class RouterOutlet extends StatefulWidget { diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart index 2c953491..4ac2647e 100644 --- a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart @@ -1,184 +1,42 @@ import 'package:flutter/material.dart'; import 'package:flutter_modular/src/presenters/navigation/modular_page.dart'; +import 'package:flutter_modular/src/presenters/navigation/modular_router_delegate.dart'; import '../../core/models/modular_router.dart'; -import '../../core/modules/child_module.dart'; -import '../interfaces/modular_navigator_interface.dart'; -import '../modular_base.dart'; -import 'route_outlet_information_parser.dart'; class RouterOutletDelegate extends RouterDelegate with // ignore: prefer_mixin ChangeNotifier, - PopNavigatorRouterDelegateMixin - implements - IModularNavigator { - final GlobalKey navigatorKey; - final RouterOutletInformationParser parser; - final Map injectMap; + PopNavigatorRouterDelegateMixin { + final GlobalKey navigatorKey = GlobalKey(); - RouterOutletDelegate(this.navigatorKey, this.parser, this.injectMap); + final ModularRouterDelegate modularRouterDelegate; - NavigatorState get navigator => navigatorKey.currentState!; + RouterOutletDelegate(this.modularRouterDelegate); - ModularRouter? _router; - - List _pages = []; - - @override - ModularRouter? get currentConfiguration => _router; - ModularRouter get lastPage => _pages.last.router; + List get routers => + modularRouterDelegate.currentConfiguration?.routerOutlet ?? []; @override Widget build(BuildContext context) { - return _pages.isEmpty + return routers.isEmpty ? Material() : Navigator( key: navigatorKey, - pages: _pages, - onPopPage: _onPopPage, + pages: routers + .map((router) => + ModularPage(key: ValueKey(router.path), router: router)) + .toList(), + onPopPage: (route, result) { + notifyListeners(); + return route.didPop(result); + }, ); } @override Future setNewRoutePath(ModularRouter router) async { - final page = ModularPage( - key: ValueKey('url:${router.path}'), - router: router, - ); - if (_pages.isEmpty) { - _pages.add(page); - } else { - _pages.last.completePop(null); - _pages.last = page; - } - _router = router; - - rebuildPages(); - } - - @override - Future navigate(String path, {arguments}) async { - var router = await parser.selectRoute(path); - router = router.copyWith(args: router.args?.copyWith(data: arguments)); - setNewRoutePath(router); - } - - bool _onPopPage(Route route, dynamic result) { - if (!route.didPop(result)) { - return false; - } - - if (route.isFirst) { - rebuildPages(); - return false; - } - - final page = route.settings as ModularPage; - final path = page.router.path; - page.completePop(result); - _pages.removeLast(); - rebuildPages(); - - final trash = []; - - injectMap.forEach((key, module) { - module.paths.remove(path); - if (module.paths.length == 0) { - module.cleanInjects(); - trash.add(key); - Modular.debugPrintModular( - "-- ${module.runtimeType.toString()} DISPOSED"); - } - }); - - for (final key in trash) { - injectMap.remove(key); - } - - return true; - } - - void rebuildPages() { - _pages = List.from(_pages); - notifyListeners(); - } - - @override - Future pushNamed(String routeName, - {Object? arguments}) async { - var router = await parser.selectRoute(routeName); - router = router.copyWith(args: router.args?.copyWith(data: arguments)); - final page = ModularPage( - key: UniqueKey(), - router: router, - ); - _pages.add(page); - rebuildPages(); - return await page.waitPop(); - } - - @override - Future pushReplacementNamed( - String routeName, - {TO? result, - Object? arguments}) async { - var router = await parser.selectRoute(routeName); - router = router.copyWith(args: router.args?.copyWith(data: arguments)); - final page = ModularPage( - key: UniqueKey(), - router: router, - ); - - _pages.last.completePop(result); - _pages.last = page; - rebuildPages(); - return await page.waitPop(); - } - - @override - Future popAndPushNamed( - String routeName, - {TO? result, - Object? arguments}) async { - _pages.last.completePop(result); - _pages.removeLast(); - return await pushNamed(routeName, arguments: arguments); - } - - @override - bool canPop() { - return navigator.canPop(); - } - - @override - Future maybePop([T? result]) => - navigator.maybePop(result); - - @override - void pop([T? result]) => navigator.pop(result); - - @override - void popUntil(bool Function(Route) predicate) => - navigator.popUntil(predicate); - - @override - Future pushNamedAndRemoveUntil( - String newRouteName, bool Function(Route) predicate, - {Object? arguments}) { - popUntil(predicate); - return pushNamed(newRouteName, arguments: arguments); - } - - @override - String get modulePath => _router!.modulePath ?? '/'; - - @override - String get path => _router!.path ?? '/'; - - @override - Future push(Route route) { - return navigator.push(route); + assert(false); } } diff --git a/flutter_modular/lib/src/presenters/widgets/navigation_listener.dart b/flutter_modular/lib/src/presenters/widgets/navigation_listener.dart new file mode 100644 index 00000000..39a14c06 --- /dev/null +++ b/flutter_modular/lib/src/presenters/widgets/navigation_listener.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +import '../modular_base.dart'; + +class NavigationListener extends StatefulWidget { + final Widget Function(BuildContext context, Widget? child) builder; + final Widget? child; + + const NavigationListener({Key? key, required this.builder, this.child}) + : super(key: key); + + @override + _NavigationListenerState createState() => _NavigationListenerState(); +} + +class _NavigationListenerState extends State { + void listener() { + setState(() {}); + } + + @override + void initState() { + super.initState(); + Modular.to.addListener(listener); + } + + @override + void dispose() { + super.dispose(); + Modular.to.removeListener(listener); + } + + @override + Widget build(BuildContext context) { + return widget.builder(context, widget.child); + } +} diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 0b38755e..b821701a 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 2.5.0-alpha.3 +version: 3.0.0-nullsafety.1 homepage: https://github.com/Flutterando/modular environment: diff --git a/flutter_modular/rocket.drawio b/flutter_modular/rocket.drawio new file mode 100644 index 00000000..16356d3b --- /dev/null +++ b/flutter_modular/rocket.drawio @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index 03273142..1fbd1c73 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -1,7 +1,9 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; +import 'package:flutter_modular/src/core/errors/errors.dart'; import 'package:flutter_modular/src/presenters/navigation/modular_route_information_parser.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -15,17 +17,20 @@ main() { final route = await parse.selectRoute('/', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, null), isA()); + expect(route.path, '/'); }); test('should retrive router /list', () async { final route = await parse.selectRoute('/list', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, null), isA()); + expect(route.path, '/list'); }); test('should retrive dynamic router /list/:id', () async { final route = await parse.selectRoute('/list/2', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, route.args).toString(), '2'); + expect(route.path, '/list/2'); }); }); @@ -34,26 +39,62 @@ main() { final route = await parse.selectRoute('/mock', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, null), isA()); + expect(route.path, '/mock'); }); test('should retrive router /mock/', () async { final route = await parse.selectRoute('/mock/', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, null), isA()); + expect(route.path, '/mock/'); }); test('should retrive router /mock/list', () async { final route = await parse.selectRoute('/mock/list', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, null), isA()); + expect(route.path, '/mock/list'); }); test('should retrive dynamic router /mock/list/:id', () async { final route = await parse.selectRoute('/mock/list/3', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, route.args).toString(), '3'); + expect(route.path, '/mock/list/3'); }); }); + + group('Outlet Module | ', () { + test('should retrive router /home/tab1', () async { + final route = await parse.selectRoute('/home/tab1', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + expect(route.path, '/home'); + expect(route.routerOutlet.length, 1); + expect(route.routerOutlet[0].child!(context, null), isA()); + expect(route.routerOutlet[0].path, '/home/tab1'); + }); + test('should retrive router /home/tab2/:id', () async { + final route = await parse.selectRoute('/home/tab2/3', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + expect(route.path, '/home'); + expect(route.routerOutlet.length, 1); + expect( + route.routerOutlet[0].child!(context, route.routerOutlet[0].args) + .toString(), + '3'); + expect(route.routerOutlet[0].path, '/home/tab2/3'); + }); + test('should throw error if not exist route /home/tab3', () async { + expect(parse.selectRoute('/home/tab3', ModuleMock()), + throwsA(isA())); + }); + }); + + test('should resolve Outlet Module Path', () async { + expect(parse.resolveOutletModulePath('/home', '/'), '/home'); + }); } class ModuleMock extends ChildModule { @@ -71,6 +112,19 @@ class ModuleMock extends ChildModule { '/', child: (context, args) => Container(), ), + ModularRouter( + '/home', + child: (context, args) => Scaffold(), + children: [ + ModularRouter('/tab1', child: (context, args) => TextField()), + ModularRouter( + '/tab2/:id', + child: (context, args) => CustomWidget( + text: args?.params!['id'], + ), + ), + ], + ), ModularRouter( '/mock', module: ModuleMock2(), From cf706d7f4243c5c97b9111f1579b717333904d4f Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 4 Dec 2020 17:21:35 -0300 Subject: [PATCH 33/71] added scaffoldMessengerKey --- flutter_modular/lib/src/presenters/modular_base.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index e13c6090..783c41b1 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -30,7 +30,7 @@ extension ModularExtension on MaterialApp { MaterialApp modular() { final app = MaterialApp.router( key: key, - // scaffoldMessengerKey: scaffoldMessengerKey, + scaffoldMessengerKey: scaffoldMessengerKey, routeInformationProvider: routeInformationProvider, backButtonDispatcher: backButtonDispatcher, builder: builder, @@ -55,7 +55,7 @@ extension ModularExtension on MaterialApp { debugShowCheckedModeBanner: debugShowCheckedModeBanner, shortcuts: shortcuts, actions: actions, - // restorationScopeId: restorationScopeId, + restorationScopeId: restorationScopeId, routeInformationParser: _routeInformationParser, routerDelegate: _routerDelegate, ); From 389add0bf9bf282499f91ab09a0cdd793da32bc9 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 4 Dec 2020 17:22:01 -0300 Subject: [PATCH 34/71] change version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index b821701a..1011b449 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.1 +version: 3.0.0-nullsafety.2 homepage: https://github.com/Flutterando/modular environment: From 639efeff571226884a063eb9bd451dccd1423b78 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 4 Dec 2020 18:04:10 -0300 Subject: [PATCH 35/71] Fix DI --- .../lib/src/core/inject/inject.dart | 23 +++++++++++++++++++ .../interfaces/modular_interface.dart | 6 +++-- .../lib/src/presenters/modular_base.dart | 1 + .../lib/src/presenters/modular_impl.dart | 7 +++--- .../src/core/modules/child_module_test.dart | 5 ++-- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/flutter_modular/lib/src/core/inject/inject.dart b/flutter_modular/lib/src/core/inject/inject.dart index 8a9df0bb..03905312 100644 --- a/flutter_modular/lib/src/core/inject/inject.dart +++ b/flutter_modular/lib/src/core/inject/inject.dart @@ -1,3 +1,6 @@ +import '../../presenters/modular_base.dart'; +import '../models/modular_arguments.dart'; + class Inject { ///!!!!NOT RECOMMENDED USE!!!! ///Bind has access to the arguments coming from the routes. @@ -7,4 +10,24 @@ class Inject { final List typesInRequest; Inject({this.params, this.typesInRequest = const []}); + + B? call({Map? params, B? defaultValue}) => + get(params: params, defaultValue: defaultValue); + + B? get({Map? params, B? defaultValue}) { + params ??= {}; + return Modular.get( + params: params, + typesInRequest: typesInRequest, + defaultValue: defaultValue, + ); + } + + ModularArguments? get args => Modular.args; + + void dispose() { + if (T.runtimeType.toString() != 'dynamic') { + Modular.dispose(); + } + } } diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart index b6f8d33a..63865fc0 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart @@ -1,9 +1,11 @@ +import 'package:flutter_modular/flutter_modular.dart'; + import '../../core/modules/child_module.dart'; import 'modular_navigator_interface.dart'; abstract class ModularInterface { bool get debugMode; - + ModularArguments? get args; String get initialRoute; ChildModule get initialModule; void init(ChildModule module); @@ -11,11 +13,11 @@ abstract class ModularInterface { void debugPrintModular(String text); IModularNavigator get to; - IModularNavigator get link; B? get({ Map params = const {}, List typesInRequest = const [], B? defaultValue, }); + void dispose(); } diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index 783c41b1..975bbd7f 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/src/presenters/router_outlet/route_outlet_information_parser.dart'; import 'package:flutter_modular/src/presenters/router_outlet/router_outlet_delegate.dart'; import '../core/modules/child_module.dart'; diff --git a/flutter_modular/lib/src/presenters/modular_impl.dart b/flutter_modular/lib/src/presenters/modular_impl.dart index 0a3d6e2b..4be6decb 100644 --- a/flutter_modular/lib/src/presenters/modular_impl.dart +++ b/flutter_modular/lib/src/presenters/modular_impl.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; +import 'package:flutter_modular/src/core/models/modular_arguments.dart'; import 'package:flutter_modular/src/core/modules/child_module.dart'; import 'interfaces/modular_interface.dart'; @@ -14,6 +15,9 @@ class ModularImpl implements ModularInterface { final Map injectMap; IModularNavigator? navigatorDelegate; + @override + ModularArguments? get args => routerDelegate.currentConfiguration?.args; + ModularImpl({ required this.routerDelegate, required this.injectMap, @@ -52,9 +56,6 @@ class ModularImpl implements ModularInterface { @override IModularNavigator get to => navigatorDelegate ?? routerDelegate; - @override - IModularNavigator get link => throw UnimplementedError(); - @override bool get debugMode => !kReleaseMode; diff --git a/flutter_modular/test/src/core/modules/child_module_test.dart b/flutter_modular/test/src/core/modules/child_module_test.dart index 75cb0b64..8924b75e 100644 --- a/flutter_modular/test/src/core/modules/child_module_test.dart +++ b/flutter_modular/test/src/core/modules/child_module_test.dart @@ -11,9 +11,10 @@ class ModuleMock extends ChildModule { @override List binds = [ Bind((i) => "Test"), + Bind.instance(1), Bind((i) => true, lazy: false), Bind((i) => StreamController(), lazy: false), - Bind((i) => ValueNotifier(0), lazy: false), + Bind((i) => ValueNotifier(i() ?? 0), lazy: false), ]; @override @@ -45,7 +46,7 @@ main() { test('should get bind', () { expect(module.getBind(typesInRequest: []), equals('Test')); expect(module.getBind(typesInRequest: []), equals(true)); - expect(module.getBind(typesInRequest: []), equals(true)); + expect(module.getBind(typesInRequest: []), equals(1)); }); test('should return null if not found bind', () { From 9b13f35033becaab1e542487d2944b2f6cd7b897 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 4 Dec 2020 18:04:41 -0300 Subject: [PATCH 36/71] b --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 1011b449..546fa4a0 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.2 +version: 3.0.0-nullsafety.3 homepage: https://github.com/Flutterando/modular environment: From a46ac79b0bb7488a73aaf32898d100facf8de0c4 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 4 Dec 2020 19:45:31 -0300 Subject: [PATCH 37/71] refact --- .../lib/src/core/modules/child_module.dart | 6 +- .../lib/src/presenters/modular_base.dart | 8 +- .../route_outlet_information_parser.dart | 180 ------------------ .../router_outlet/router_outlet.dart | 101 ---------- 4 files changed, 5 insertions(+), 290 deletions(-) delete mode 100644 flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart delete mode 100644 flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/modules/child_module.dart index 5dde4318..f2557d19 100644 --- a/flutter_modular/lib/src/core/modules/child_module.dart +++ b/flutter_modular/lib/src/core/modules/child_module.dart @@ -7,10 +7,8 @@ import '../interfaces/disposable.dart'; import '../models/modular_router.dart'; abstract class ChildModule { - late final List binds; - late final List routers; - - ChildModule(); + late List binds; + late List routers; @visibleForTesting void changeBinds(List b) { diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index 975bbd7f..a4425e19 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -1,14 +1,12 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/src/presenters/router_outlet/route_outlet_information_parser.dart'; -import 'package:flutter_modular/src/presenters/router_outlet/router_outlet_delegate.dart'; -import '../core/modules/child_module.dart'; +import '../../flutter_modular.dart'; +import '../core/modules/child_module.dart'; import 'interfaces/modular_interface.dart'; import 'modular_impl.dart'; import 'navigation/modular_route_information_parser.dart'; import 'navigation/modular_router_delegate.dart'; -import 'router_outlet/router_outlet.dart'; +import 'router_outlet/router_outlet_delegate.dart'; final _navigatorKey = GlobalKey(); diff --git a/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart b/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart deleted file mode 100644 index 87b5eafb..00000000 --- a/flutter_modular/lib/src/presenters/router_outlet/route_outlet_information_parser.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../core/errors/errors.dart'; -import '../../core/models/modular_router.dart'; -import '../../core/modules/child_module.dart'; - -import '../modular_base.dart'; - -class RouterOutletInformationParser - extends RouteInformationParser { - @override - Future parseRouteInformation( - RouteInformation routeInformation) async { - final path = routeInformation.location ?? '/'; - final route = await selectRoute(path); - return route; - } - - @override - RouteInformation restoreRouteInformation(ModularRouter router) { - return RouteInformation(location: router.path); - } - - ModularRouter? _searchInModule( - ChildModule module, String routerName, String path) { - path = "/$path".replaceAll('//', '/'); - final routers = - module.routers.map((e) => e.copyWith(currentModule: module)).toList(); - routers.sort((preview, actual) { - return preview.routerName.contains('/:') ? 1 : 0; - }); - for (var route in routers) { - var r = _searchRoute(route, routerName, path); - if (r != null) { - return r; - } - } - return null; - } - - ModularRouter? _normalizeRoute( - ModularRouter route, String routerName, String path) { - ModularRouter? router; - if (routerName == path || routerName == "$path/") { - router = route.module!.routers[0]; - if (router.module != null) { - var _routerName = - (routerName + route.routerName).replaceFirst('//', '/'); - router = _searchInModule(route.module!, _routerName, path); - } - } else { - router = _searchInModule(route.module!, routerName, path); - } - return router; - } - - ModularRouter? _searchRoute( - ModularRouter route, String routerName, String path) { - final tempRouteName = - (routerName + route.routerName).replaceFirst('//', '/'); - if (route.child == null) { - var _routerName = - ('$routerName${route.routerName}/').replaceFirst('//', '/'); - var router = _normalizeRoute(route, _routerName, path); - - if (router != null) { - router = router.copyWith( - modulePath: router.modulePath == null ? '/' : tempRouteName, - path: path, - ); - - if (router.transition == TransitionType.defaultTransition) { - router = router.copyWith( - transition: route.transition, - customTransition: route.customTransition, - ); - } - if (route.module != null) { - Modular.bindModule(route.module!, path); - } - return router; - } - } else { - if (tempRouteName.split('/').length != path.split('/').length) { - return null; - } - - var parseRoute = _parseUrlParams(route, tempRouteName, path); - - if (path != parseRoute.path) { - return null; - } - - if (parseRoute.currentModule != null) { - Modular.bindModule(parseRoute.currentModule!, path); - return parseRoute; - } - } - - return null; - } - - String prepareToRegex(String url) { - final newUrl = []; - for (var part in url.split('/')) { - var url = part.contains(":") ? "(.*?)" : part; - newUrl.add(url); - } - - return newUrl.join("/"); - } - - ModularRouter _parseUrlParams( - ModularRouter router, String routeNamed, String path) { - if (routeNamed.contains('/:')) { - final regExp = RegExp( - "^${prepareToRegex(routeNamed)}\$", - caseSensitive: true, - ); - var r = regExp.firstMatch(path); - if (r != null) { - var params = {}; - var paramPos = 0; - final routeParts = routeNamed.split('/'); - final pathParts = path.split('/'); - - // print('Match! Processing $path as $routeNamed'); - - for (var routePart in routeParts) { - if (routePart.contains(":")) { - var paramName = routePart.replaceFirst(':', ''); - if (pathParts[paramPos].isNotEmpty) { - params[paramName] = pathParts[paramPos]; - routeNamed = - routeNamed.replaceFirst(routePart, params[paramName]!); - } - } - paramPos++; - } - - return router.copyWith( - args: router.args!.copyWith(params: params), path: routeNamed); - } - - return router.copyWith( - args: router.args!.copyWith(params: null), path: routeNamed); - } - - return router.copyWith(path: routeNamed); - } - - Future selectRoute(String path, [ChildModule? module]) async { - if (path.isEmpty) { - throw Exception("Router can not be empty"); - } - var route = _searchInModule(module ?? Modular.initialModule, "", path); - return canActivate(path, route); - } - - Future canActivate(String path, ModularRouter? router) async { - if (router == null) { - throw ModularError('Route not found'); - } - - if (router.guards?.isNotEmpty == true) { - for (var guard in router.guards!) { - try { - final result = await guard.canActivate(path, router); - if (!result) { - throw ModularError('$path is NOT ACTIVATE'); - } - // ignore: avoid_catches_without_on_clauses - } catch (e) { - throw ModularError( - 'RouteGuard error. Check ($path) in ${router.currentModule.runtimeType}'); - } - } - } - return router; - } -} diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart deleted file mode 100644 index 91aa32aa..00000000 --- a/flutter_modular/lib/src/presenters/router_outlet/router_outlet.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import 'package:flutter_modular/src/core/models/modular_router.dart'; -import 'package:flutter_modular/src/presenters/modular_base.dart'; -import 'package:flutter_modular/src/presenters/navigation/modular_router_delegate.dart'; - -import 'route_outlet_information_parser.dart'; -import 'router_outlet_delegate.dart'; - -// class RouterOutlet extends StatelessWidget { -// final navigatorKey = GlobalKey(); -// final parser = RouterOutletInformationParser(); -// final provider = Providerd(); -// late final delegate = RouterOutletDelegate(navigatorKey, parser, {}); - -// @override -// Widget build(BuildContext context) { - -// return Router( -// routeInformationProvider: provider, -// routeInformationParser: parser, -// routerDelegate: delegate, -// ); -// } -// } - -class Providerd extends RouteInformationProvider { - final ModularRouterDelegate _delegate; - Providerd(this._delegate); - - @override - void addListener(listener) { - print(listener); - print(Modular.to.path); - } - - @override - void removeListener(listener) { - print('removeListener'); - } - - @override - RouteInformation? get value => RouteInformation(location: '/other'); -} - -// class RouterOutlet extends StatefulWidget { -// final ChildModule module; -// final String initialRoute; -// final Key navigatorKey; -// final bool keepAlive; -// final void Function(String route) onChangeRoute; - -// RouterOutlet({ -// Key key, -// @required this.module, -// this.navigatorKey, -// this.initialRoute = '/', -// this.keepAlive = true, -// this.onChangeRoute, -// }) : super(key: key) { -// module.paths.add(runtimeType.toString()); -// } - -// @override -// _RouterOutletState createState() => _RouterOutletState(); -// } - -// class _RouterOutletState extends State -// with AutomaticKeepAliveClientMixin { -// GlobalKey _key; -// @override -// void initState() { -// super.initState(); -// // _key = widget.navigatorKey ?? -// // Modular.outletNavigatorKey(widget.module.runtimeType.toString()); -// } - -// @override -// Widget build(BuildContext context) { -// super.build(context); -// return WillPopScope( -// onWillPop: () async { -// return !await _key.currentState.maybePop(); -// }, -// child: ModularProvider( -// module: widget.module, -// child: Navigator( -// key: _key, -// initialRoute: widget.initialRoute, -// // onGenerateRoute: (setting) { -// // return Modular.generateRoute( -// // setting, widget.module, widget.onChangeRoute); -// // }, -// ), -// ), -// ); -// } - -// @override -// bool get wantKeepAlive => widget.keepAlive; -// } From 7cfa31446af07b0aa82c131b3d3007a1f79eeb41 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Fri, 4 Dec 2020 20:48:43 -0300 Subject: [PATCH 38/71] change version --- flutter_modular/lib/src/core/inject/inject.dart | 2 +- .../src/presenters/interfaces/modular_interface.dart | 2 +- flutter_modular/lib/src/presenters/modular_impl.dart | 12 +++++++----- flutter_modular/pubspec.yaml | 2 +- .../test/src/core/modules/child_module_test.dart | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/flutter_modular/lib/src/core/inject/inject.dart b/flutter_modular/lib/src/core/inject/inject.dart index 03905312..2b3ba01c 100644 --- a/flutter_modular/lib/src/core/inject/inject.dart +++ b/flutter_modular/lib/src/core/inject/inject.dart @@ -18,7 +18,7 @@ class Inject { params ??= {}; return Modular.get( params: params, - typesInRequest: typesInRequest, + typesInRequestList: typesInRequest, defaultValue: defaultValue, ); } diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart index 63865fc0..7781d85f 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart @@ -15,7 +15,7 @@ abstract class ModularInterface { IModularNavigator get to; B? get({ Map params = const {}, - List typesInRequest = const [], + List? typesInRequestList, B? defaultValue, }); diff --git a/flutter_modular/lib/src/presenters/modular_impl.dart b/flutter_modular/lib/src/presenters/modular_impl.dart index 4be6decb..6ef8089f 100644 --- a/flutter_modular/lib/src/presenters/modular_impl.dart +++ b/flutter_modular/lib/src/presenters/modular_impl.dart @@ -65,8 +65,9 @@ class ModularImpl implements ModularInterface { @override B get( {Map params = const {}, - List typesInRequest = const [], + List? typesInRequestList, B? defaultValue}) { + var typesInRequest = typesInRequestList ?? []; if (B.toString() == 'dynamic') { throw ModularError('not allow for dynamic values'); } @@ -74,11 +75,11 @@ class ModularImpl implements ModularInterface { if (typesInRequest.isEmpty) { final module = routerDelegate - .currentConfiguration?.currentModule.runtimeType + .currentConfiguration?.currentModule?.runtimeType .toString() ?? '=global'; result = _getInjectableObject(module, - params: params, typesInRequest: typesInRequest); + params: params, typesInRequestList: typesInRequest); } if (result != null) { @@ -87,7 +88,7 @@ class ModularImpl implements ModularInterface { for (var key in injectMap.keys) { final value = _getInjectableObject(key, - params: params, typesInRequest: typesInRequest, checkKey: false); + params: params, typesInRequestList: typesInRequest, checkKey: false); if (value != null) { return value; } @@ -103,10 +104,11 @@ class ModularImpl implements ModularInterface { B? _getInjectableObject( String tag, { Map params = const {}, - List typesInRequest = const [], + List? typesInRequestList, bool checkKey = true, }) { B? value; + var typesInRequest = typesInRequestList ?? []; if (!checkKey) { value = injectMap[tag] ?.getBind(params: params, typesInRequest: typesInRequest); diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 546fa4a0..6a0db6b5 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.3 +version: 3.0.0-nullsafety.4 homepage: https://github.com/Flutterando/modular environment: diff --git a/flutter_modular/test/src/core/modules/child_module_test.dart b/flutter_modular/test/src/core/modules/child_module_test.dart index 8924b75e..a8e22b53 100644 --- a/flutter_modular/test/src/core/modules/child_module_test.dart +++ b/flutter_modular/test/src/core/modules/child_module_test.dart @@ -14,7 +14,7 @@ class ModuleMock extends ChildModule { Bind.instance(1), Bind((i) => true, lazy: false), Bind((i) => StreamController(), lazy: false), - Bind((i) => ValueNotifier(i() ?? 0), lazy: false), + Bind((i) => ValueNotifier(0), lazy: false), ]; @override From 449b1188c2c36f9620fbc17ca1a3928ca2f7bf47 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 5 Dec 2020 13:26:19 -0300 Subject: [PATCH 39/71] url notify change --- .../lib/src/presenters/modular_base.dart | 3 --- .../modular_route_information_parser.dart | 1 - .../navigation/modular_router_delegate.dart | 20 +++++++++++++------ .../router_outlet/router_outlet_delegate.dart | 1 + 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index a4425e19..0b13c412 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -8,13 +8,10 @@ import 'navigation/modular_route_information_parser.dart'; import 'navigation/modular_router_delegate.dart'; import 'router_outlet/router_outlet_delegate.dart'; -final _navigatorKey = GlobalKey(); - final Map _injectMap = {}; final _routeInformationParser = ModularRouteInformationParser(); final _routerDelegate = ModularRouterDelegate( - _navigatorKey, _routeInformationParser, _injectMap, ); diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index d48086fc..faf818d4 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -10,7 +10,6 @@ class ModularRouteInformationParser @override Future parseRouteInformation( RouteInformation routeInformation) async { - print(routeInformation); final path = routeInformation.location ?? '/'; final route = await selectRoute(path); return route; diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index ebc1f1c0..facf2c15 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import '../../core/models/modular_router.dart'; import '../../core/modules/child_module.dart'; @@ -14,18 +15,25 @@ class ModularRouterDelegate extends RouterDelegate PopNavigatorRouterDelegateMixin implements IModularNavigator { - final GlobalKey navigatorKey; + final GlobalKey navigatorKey = GlobalKey(); final ModularRouteInformationParser parser; final Map injectMap; - ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); + ModularRouterDelegate(this.parser, this.injectMap) { + SystemChannels.navigation.setMethodCallHandler((call) async { + if ('pushRouteInformation' == call.method) { + navigate(call.arguments['location']); + } + }); + } NavigatorState get navigator => navigatorKey.currentState!; List _pages = []; @override - ModularRouter? get currentConfiguration => _pages.last.router; + ModularRouter? get currentConfiguration => + _pages.isEmpty ? null : _pages.last.router; @override Widget build(BuildContext context) { @@ -40,8 +48,6 @@ class ModularRouterDelegate extends RouterDelegate @override Future setNewRoutePath(ModularRouter router) async { - print('setNewRoutePath: ${router.routerOutlet.length}'); - final page = ModularPage( key: ValueKey('url:${router.path}'), router: router, @@ -59,7 +65,9 @@ class ModularRouterDelegate extends RouterDelegate @override Future navigate(String routeName, {arguments, bool linked = false}) async { - print('navigate: $routeName'); + if (routeName == path) { + return; + } var router = await parser.selectRoute(linked ? modulePath + routeName : routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart index 4ac2647e..7158659c 100644 --- a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_modular/src/presenters/navigation/modular_page.dart'; import 'package:flutter_modular/src/presenters/navigation/modular_router_delegate.dart'; From 6c0c4e41d2c6187e9936ecf1c3c6c6bd3ff7778b Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 5 Dec 2020 13:30:55 -0300 Subject: [PATCH 40/71] change version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 6a0db6b5..fe59a841 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.4 +version: 3.0.0-nullsafety.5 homepage: https://github.com/Flutterando/modular environment: From a89c67b6c889b43d67ca9baf44f1d5f8a1c250fc Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 5 Dec 2020 19:20:42 -0300 Subject: [PATCH 41/71] fix module router outlet --- .../modular_route_information_parser.dart | 5 +++-- flutter_modular/pubspec.yaml | 2 +- .../modular_route_information_parse_test.dart | 21 ++++++++++++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index faf818d4..5e19c6eb 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -50,6 +50,8 @@ class ModularRouteInformationParser var _routerName = (routerName + route.routerName).replaceFirst('//', '/'); router = _searchInModule(route.module!, _routerName, path); + } else { + router = router.copyWith(path: routerName); } } else { router = _searchInModule(route.module!, routerName, path); @@ -69,7 +71,6 @@ class ModularRouteInformationParser if (router != null) { router = router.copyWith( modulePath: router.modulePath == null ? '/' : tempRouteName, - path: path, ); if (router.transition == TransitionType.defaultTransition) { @@ -86,7 +87,7 @@ class ModularRouteInformationParser } else { if (route.children.isNotEmpty) { for (var routeChild in route.children) { - var r = _searchRoute(routeChild, route.routerName, path); + var r = _searchRoute(routeChild, tempRouteName, path); if (r != null) { route = route.copyWith(routerOutlet: [ r.copyWith( diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index fe59a841..88d9dee1 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.5 +version: 3.0.0-nullsafety.6 homepage: https://github.com/Flutterando/modular environment: diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index 1fbd1c73..cb384491 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_modular/src/presenters/navigation/modular_route_informat import 'package:flutter_test/flutter_test.dart'; main() { + WidgetsFlutterBinding.ensureInitialized(); var parse = ModularRouteInformationParser(); BuildContext context = Container().createElement(); @@ -39,7 +40,7 @@ main() { final route = await parse.selectRoute('/mock', ModuleMock()); expect(route, isNotNull); expect(route.child!(context, null), isA()); - expect(route.path, '/mock'); + expect(route.path, '/mock/'); }); test('should retrive router /mock/', () async { @@ -90,6 +91,17 @@ main() { expect(parse.selectRoute('/home/tab3', ModuleMock()), throwsA(isA())); }); + + test('should retrive router (Module)', () async { + final route = await parse.selectRoute('/mock/home', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + expect(route.path, '/mock/'); + expect(route.modulePath, '/mock'); + expect(route.routerOutlet.length, 1); + expect(route.routerOutlet[0].child!(context, null), isA()); + expect(route.routerOutlet[0].path, '/mock/home'); + }); }); test('should resolve Outlet Module Path', () async { @@ -153,10 +165,9 @@ class ModuleMock2 extends ChildModule { @override List routers = [ - ModularRouter( - '/', - child: (context, args) => SizedBox(), - ), + ModularRouter('/', child: (context, args) => SizedBox(), children: [ + ModularRouter('/home', child: (context, args) => Container()), + ]), ModularRouter( '/list', child: (context, args) => ListView(), From fcb79dd31b9237a06053d71e14125b19e18cb9f0 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 5 Dec 2020 21:13:59 -0300 Subject: [PATCH 42/71] fix pop router --- .../lib/src/presenters/modular_base.dart | 17 ++++++-- .../presenters/navigation/modular_page.dart | 15 +++---- .../navigation/modular_router_delegate.dart | 6 +-- .../router_outlet/router_outlet_delegate.dart | 41 ++++++++++++++----- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index 0b13c412..760ee285 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -60,9 +60,20 @@ extension ModularExtension on MaterialApp { } } -class RouterOutlet extends StatelessWidget { - final navigatorKey = GlobalKey(); - late final delegate = RouterOutletDelegate(_routerDelegate); +class RouterOutlet extends StatefulWidget { + @override + _RouterOutletState createState() => _RouterOutletState(); +} + +class _RouterOutletState extends State { + late GlobalKey navigatorKey; + late RouterOutletDelegate delegate; + @override + void initState() { + super.initState(); + navigatorKey = GlobalKey(); + delegate = RouterOutletDelegate(_routerDelegate, navigatorKey); + } @override Widget build(BuildContext context) { diff --git a/flutter_modular/lib/src/presenters/navigation/modular_page.dart b/flutter_modular/lib/src/presenters/navigation/modular_page.dart index 3679236b..7b1ff016 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_page.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_page.dart @@ -12,19 +12,20 @@ class ModularPage extends Page { ModularPage({LocalKey? key, required this.router}) : super(key: key, name: router.path, arguments: router.args?.data); - Future waitPop() { + Future waitPop() { if (_allCompleters.containsKey(hashCode)) { - return (_allCompleters[hashCode] as Completer).future; + return (_allCompleters[hashCode] as Completer).future; } else { - _allCompleters[hashCode] = Completer(); - return (_allCompleters[hashCode] as Completer).future; + _allCompleters[hashCode] = Completer(); + return (_allCompleters[hashCode] as Completer).future; } } - void completePop(T result) { + void completePop(T? result) { if (_allCompleters.containsKey(hashCode) && - !(_allCompleters[hashCode] as Completer).isCompleted) { - (_allCompleters[hashCode] as Completer).complete(result); + !(_allCompleters[hashCode] as Completer).isCompleted) { + final complete = (_allCompleters[hashCode] as Completer); + complete.complete(result); _allCompleters.remove(hashCode); } } diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index facf2c15..e277dd1e 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -115,7 +115,7 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future pushNamed(String routeName, + Future pushNamed(String routeName, {Object? arguments, bool linked = false}) async { var router = await parser.selectRoute(linked ? modulePath + routeName : routeName); @@ -150,7 +150,7 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future popAndPushNamed( + Future popAndPushNamed( String routeName, {TO? result, Object? arguments, @@ -177,7 +177,7 @@ class ModularRouterDelegate extends RouterDelegate navigator.popUntil(predicate); @override - Future pushNamedAndRemoveUntil( + Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, {Object? arguments, bool linked = false}) { popUntil(predicate); diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart index 7158659c..95c1eae4 100644 --- a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart @@ -1,34 +1,53 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_modular/src/presenters/navigation/modular_page.dart'; -import 'package:flutter_modular/src/presenters/navigation/modular_router_delegate.dart'; import '../../core/models/modular_router.dart'; +import '../navigation/modular_page.dart'; +import '../navigation/modular_router_delegate.dart'; + +final _pages = >{}; class RouterOutletDelegate extends RouterDelegate with // ignore: prefer_mixin ChangeNotifier, PopNavigatorRouterDelegateMixin { - final GlobalKey navigatorKey = GlobalKey(); + final GlobalKey navigatorKey; final ModularRouterDelegate modularRouterDelegate; - RouterOutletDelegate(this.modularRouterDelegate); + RouterOutletDelegate(this.modularRouterDelegate, this.navigatorKey) { + _getPages(); + } + + List pages = []; + + List _getPages() { + final newPages = routers + .map( + (router) => ModularPage(key: ValueKey(router.path), router: router)) + .toList(); + + if (pages.isEmpty) { + pages = newPages; + return pages; + } else if (newPages.isNotEmpty && + newPages.last.router.modulePath == pages.last.router.modulePath) { + pages = newPages; + return pages; + } + + return pages; + } List get routers => modularRouterDelegate.currentConfiguration?.routerOutlet ?? []; @override Widget build(BuildContext context) { - return routers.isEmpty + return pages.isEmpty ? Material() : Navigator( - key: navigatorKey, - pages: routers - .map((router) => - ModularPage(key: ValueKey(router.path), router: router)) - .toList(), + pages: _getPages(), onPopPage: (route, result) { notifyListeners(); return route.didPop(result); From 0e8166ab96c066655ef4909c984665dbb80ae3b7 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 5 Dec 2020 21:18:06 -0300 Subject: [PATCH 43/71] change version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 88d9dee1..06322d1d 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.6 +version: 3.0.0-nullsafety.7 homepage: https://github.com/Flutterando/modular environment: From 85ce39a819ac74ce01dc177ba5c14b4e2838b802 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 5 Dec 2020 22:19:53 -0300 Subject: [PATCH 44/71] remove unused variables --- .../src/presenters/router_outlet/router_outlet_delegate.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart index 95c1eae4..c37e2cfe 100644 --- a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart @@ -4,8 +4,6 @@ import '../../core/models/modular_router.dart'; import '../navigation/modular_page.dart'; import '../navigation/modular_router_delegate.dart'; -final _pages = >{}; - class RouterOutletDelegate extends RouterDelegate with // ignore: prefer_mixin From c6a66d66910ded86236384e7e22afb44396ae0b4 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 6 Dec 2020 14:09:30 -0300 Subject: [PATCH 45/71] change binds --- .../lib/src/core/modules/child_module.dart | 4 +-- .../lib/src/presenters/modular_base.dart | 2 +- .../modular_route_information_parser.dart | 2 +- .../navigation/modular_router_delegate.dart | 27 +++++++++++++------ .../router_outlet_delegate.dart | 11 +++++--- 5 files changed, 31 insertions(+), 15 deletions(-) rename flutter_modular/lib/src/presenters/{router_outlet => navigation}/router_outlet_delegate.dart (83%) diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/modules/child_module.dart index f2557d19..23baded8 100644 --- a/flutter_modular/lib/src/core/modules/child_module.dart +++ b/flutter_modular/lib/src/core/modules/child_module.dart @@ -7,8 +7,8 @@ import '../interfaces/disposable.dart'; import '../models/modular_router.dart'; abstract class ChildModule { - late List binds; - late List routers; + List binds = []; + List routers = []; @visibleForTesting void changeBinds(List b) { diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index 760ee285..3ad5fa62 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -6,7 +6,7 @@ import 'interfaces/modular_interface.dart'; import 'modular_impl.dart'; import 'navigation/modular_route_information_parser.dart'; import 'navigation/modular_router_delegate.dart'; -import 'router_outlet/router_outlet_delegate.dart'; +import 'navigation/router_outlet_delegate.dart'; final Map _injectMap = {}; diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 5e19c6eb..3bd43fb1 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -186,7 +186,7 @@ class ModularRouteInformationParser Future canActivate(String path, ModularRouter? router) async { if (router == null) { - throw ModularError('Route not found'); + throw ModularError('Route \'$path\' not found'); } if (router.guards?.isNotEmpty == true) { diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index e277dd1e..c44c6b55 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -55,7 +55,7 @@ class ModularRouterDelegate extends RouterDelegate if (_pages.isEmpty) { _pages.add(page); } else { - _pages.last.completePop(null); + _pages.last.router.completePop(null); _pages.last = page; } @@ -86,7 +86,7 @@ class ModularRouterDelegate extends RouterDelegate final page = route.settings as ModularPage; final path = page.router.path; - page.completePop(result); + page.router.completePop(result); _pages.removeLast(); rebuildPages(); @@ -124,9 +124,20 @@ class ModularRouterDelegate extends RouterDelegate key: UniqueKey(), router: router, ); - _pages.add(page); - rebuildPages(); - return await page.waitPop(); + + if (router.routerOutlet.isNotEmpty && router == _pages.last.router) { + _pages.last.router.routerOutlet.add(router.routerOutlet.last.copyWith( + args: router.args?.copyWith(data: arguments), + )); + notifyListeners(); + final result = await page.router.waitPop(); + rebuildPages(); + return result; + } else { + _pages.add(page); + rebuildPages(); + return await page.router.waitPop(); + } } @override @@ -143,10 +154,10 @@ class ModularRouterDelegate extends RouterDelegate router: router, ); - _pages.last.completePop(result); + _pages.last.router.completePop(result); _pages.last = page; rebuildPages(); - return await page.waitPop(); + return await page.router.waitPop(); } @override @@ -155,7 +166,7 @@ class ModularRouterDelegate extends RouterDelegate {TO? result, Object? arguments, bool linked = false}) async { - _pages.last.completePop(result); + _pages.last.router.completePop(result); _pages.removeLast(); return await pushNamed(routeName, arguments: arguments, linked: linked); } diff --git a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart similarity index 83% rename from flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart rename to flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart index c37e2cfe..186f7210 100644 --- a/flutter_modular/lib/src/presenters/router_outlet/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import '../../core/models/modular_router.dart'; -import '../navigation/modular_page.dart'; -import '../navigation/modular_router_delegate.dart'; +import 'modular_page.dart'; +import 'modular_router_delegate.dart'; class RouterOutletDelegate extends RouterDelegate with @@ -47,7 +47,12 @@ class RouterOutletDelegate extends RouterDelegate : Navigator( pages: _getPages(), onPopPage: (route, result) { - notifyListeners(); + if (routers.length > 1) { + final page = route.settings as ModularPage; + routers.removeLast(); + page.router.completePop(result); + } + return route.didPop(result); }, ); From 239546d5f3dcb858aa0f6f11221978f408905705 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 8 Dec 2020 13:29:46 -0300 Subject: [PATCH 46/71] Implemented Native Pushs --- .../lib/src/core/models/modular_router.dart | 3 +- .../modular_navigator_interface.dart | 8 +- .../navigation/modular_router_delegate.dart | 153 +++++++++++++----- .../navigation/router_outlet_delegate.dart | 43 +++-- .../modular_route_information_parse_test.dart | 7 + 5 files changed, 150 insertions(+), 64 deletions(-) diff --git a/flutter_modular/lib/src/core/models/modular_router.dart b/flutter_modular/lib/src/core/models/modular_router.dart index 50264da8..0532770b 100644 --- a/flutter_modular/lib/src/core/models/modular_router.dart +++ b/flutter_modular/lib/src/core/models/modular_router.dart @@ -213,7 +213,8 @@ class ModularRouter { customTransition != null) || transition != TransitionType.custom && customTransition == null), assert((module == null && child != null) || - (module != null && child == null)); + (module != null && child == null)), + assert(routerName == '**' ? child != null : true); ModularRouter copyWith( {ModularChild? child, diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart index bb91d7fe..8cef7218 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart @@ -28,7 +28,7 @@ abstract class IModularNavigator { String routeName, {TO result, Object arguments, - bool linked = false}); + bool forRoot = false}); /// Navigate to a route. /// @@ -40,7 +40,7 @@ abstract class IModularNavigator { /// Modular.to.pushNamed('/home', arguments: 10); /// ``` Future pushNamed(String routeName, - {Object arguments, bool linked = false}); + {Object arguments, bool forRoot = false}); /// Push the route with the given name onto the navigator that most tightly /// encloses the given context, and then remove all the previous routes until @@ -55,7 +55,7 @@ abstract class IModularNavigator { /// ``` Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, - {Object arguments, bool linked = false}); + {Object arguments, bool forRoot = false}); ///Replace the current route of the navigator that most tightly encloses the ///given context by pushing the route named routeName and then disposing the @@ -72,7 +72,7 @@ abstract class IModularNavigator { String routeName, {TO result, Object arguments, - bool linked = false}); + bool forRoot = false}); /// Removes the current Route from the stack of routes. /// diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index c44c6b55..c52bf6d4 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -30,6 +30,7 @@ class ModularRouterDelegate extends RouterDelegate NavigatorState get navigator => navigatorKey.currentState!; List _pages = []; + final routerOutlatPages = >{}; @override ModularRouter? get currentConfiguration => @@ -47,7 +48,8 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future setNewRoutePath(ModularRouter router) async { + Future setNewRoutePath(ModularRouter router, + [bool execRebuild = true]) async { final page = ModularPage( key: ValueKey('url:${router.path}'), router: router, @@ -55,11 +57,15 @@ class ModularRouterDelegate extends RouterDelegate if (_pages.isEmpty) { _pages.add(page); } else { - _pages.last.router.completePop(null); - _pages.last = page; + for (var p in _pages) { + p.completePop(null); + } + _pages = [page]; } - rebuildPages(); + if (execRebuild) { + rebuildPages(); + } } @override @@ -71,7 +77,13 @@ class ModularRouterDelegate extends RouterDelegate var router = await parser.selectRoute(linked ? modulePath + routeName : routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); - setNewRoutePath(router); + setNewRoutePath(router, false); + if (router.routerOutlet.isNotEmpty) { + routerOutlatPages[router.path!] = router.routerOutlet + .map((e) => ModularPage(key: ValueKey(e.path), router: e)) + .toList(); + } + rebuildPages(); } bool _onPopPage(Route route, dynamic result) { @@ -85,11 +97,19 @@ class ModularRouterDelegate extends RouterDelegate } final page = route.settings as ModularPage; - final path = page.router.path; - page.router.completePop(result); + final path = page.router.path!; + page.completePop(result); + removeInject(path); + for (var r in page.router.routerOutlet) { + removeInject(r.path!); + } _pages.removeLast(); rebuildPages(); + return true; + } + + removeInject(String path) { final trash = []; injectMap.forEach((key, module) { @@ -105,8 +125,6 @@ class ModularRouterDelegate extends RouterDelegate for (final key in trash) { injectMap.remove(key); } - - return true; } void rebuildPages() { @@ -116,48 +134,92 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamed(String routeName, - {Object? arguments, bool linked = false}) async { - var router = - await parser.selectRoute(linked ? modulePath + routeName : routeName); + {Object? arguments, bool forRoot = false}) async { + var router = await parser.selectRoute(routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); - final page = ModularPage( - key: UniqueKey(), - router: router, - ); - if (router.routerOutlet.isNotEmpty && router == _pages.last.router) { - _pages.last.router.routerOutlet.add(router.routerOutlet.last.copyWith( + if (router.routerOutlet.isNotEmpty) { + final outletRouter = router.routerOutlet.last.copyWith( args: router.args?.copyWith(data: arguments), - )); - notifyListeners(); - final result = await page.router.waitPop(); - rebuildPages(); - return result; + ); + final page = ModularPage( + key: UniqueKey(), + router: outletRouter, + ); + + if (forRoot) { + _pages.add(page); + rebuildPages(); + return await page.waitPop(); + } else { + routerOutlatPages[router.path!]?.add(page); + currentConfiguration?.routerOutlet.add(router); + notifyListeners(); + final result = await page.waitPop(); + routerOutlatPages[router.path!]?.removeLast(); + currentConfiguration?.routerOutlet.removeLast(); + notifyListeners(); + return result; + } } else { + final page = ModularPage( + key: UniqueKey(), + router: router, + ); _pages.add(page); rebuildPages(); - return await page.router.waitPop(); + return await page.waitPop(); } } @override - Future pushReplacementNamed( + Future pushReplacementNamed( String routeName, {TO? result, Object? arguments, - bool linked = false}) async { - var router = - await parser.selectRoute(linked ? modulePath + routeName : routeName); + bool forRoot = false}) async { + var router = await parser.selectRoute(routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); - final page = ModularPage( - key: UniqueKey(), - router: router, - ); - _pages.last.router.completePop(result); - _pages.last = page; - rebuildPages(); - return await page.router.waitPop(); + if (router.routerOutlet.isNotEmpty) { + final outletRouter = router.routerOutlet.last.copyWith( + args: router.args?.copyWith(data: arguments), + ); + final page = ModularPage( + key: UniqueKey(), + router: outletRouter, + ); + + if (forRoot) { + final lastPage = _pages.last; + _pages.last = page; + rebuildPages(); + final result = await page.waitPop(); + lastPage.completePop(result); + return result; + } else { + final lastPage = routerOutlatPages[router.path!]?.last; + routerOutlatPages[router.path!]?.last = page; + currentConfiguration?.routerOutlet.last = router; + notifyListeners(); + final result = await page.waitPop(); + lastPage!.completePop(result); + notifyListeners(); + return result; + } + } else { + final page = ModularPage( + key: UniqueKey(), + router: router, + ); + + final lastPage = _pages.last; + _pages.last = page; + rebuildPages(); + final result = await page.waitPop(); + lastPage.completePop(result); + return result; + } } @override @@ -165,10 +227,17 @@ class ModularRouterDelegate extends RouterDelegate String routeName, {TO? result, Object? arguments, - bool linked = false}) async { - _pages.last.router.completePop(result); - _pages.removeLast(); - return await pushNamed(routeName, arguments: arguments, linked: linked); + bool forRoot = false}) async { + var router = await parser.selectRoute(routeName); + if (!forRoot && router.routerOutlet.isNotEmpty) { + routerOutlatPages[router.path!]?.last.completePop(result); + } else { + _pages.last.completePop(result); + _pages.removeLast(); + } + + return await pushNamed(routeName, + arguments: arguments, forRoot: forRoot); } @override @@ -190,9 +259,9 @@ class ModularRouterDelegate extends RouterDelegate @override Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, - {Object? arguments, bool linked = false}) { + {Object? arguments, bool forRoot = false}) { popUntil(predicate); - return pushNamed(newRouteName, arguments: arguments, linked: linked); + return pushNamed(newRouteName, arguments: arguments, forRoot: forRoot); } @override diff --git a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart index 186f7210..d43f5fc6 100644 --- a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../../core/models/modular_router.dart'; +import '../modular_base.dart'; import 'modular_page.dart'; import 'modular_router_delegate.dart'; @@ -12,34 +13,28 @@ class RouterOutletDelegate extends RouterDelegate final GlobalKey navigatorKey; final ModularRouterDelegate modularRouterDelegate; + late String path; RouterOutletDelegate(this.modularRouterDelegate, this.navigatorKey) { + path = modularRouterDelegate.currentConfiguration!.path!; _getPages(); } List pages = []; List _getPages() { - final newPages = routers - .map( - (router) => ModularPage(key: ValueKey(router.path), router: router)) - .toList(); - - if (pages.isEmpty) { - pages = newPages; - return pages; - } else if (newPages.isNotEmpty && - newPages.last.router.modulePath == pages.last.router.modulePath) { - pages = newPages; + if (modularRouterDelegate.currentConfiguration?.path != path) { return pages; } + if (modularRouterDelegate.routerOutlatPages.containsKey(path)) { + final list = modularRouterDelegate.routerOutlatPages[path] ?? []; + pages = [...list]; + } + return pages; } - List get routers => - modularRouterDelegate.currentConfiguration?.routerOutlet ?? []; - @override Widget build(BuildContext context) { return pages.isEmpty @@ -47,10 +42,24 @@ class RouterOutletDelegate extends RouterDelegate : Navigator( pages: _getPages(), onPopPage: (route, result) { - if (routers.length > 1) { + if (pages.length > 1) { final page = route.settings as ModularPage; - routers.removeLast(); - page.router.completePop(result); + final path = page.router.path; + page.completePop(result); + final trash = []; + modularRouterDelegate.injectMap.forEach((key, module) { + module.paths.remove(path); + if (module.paths.length == 0) { + module.cleanInjects(); + trash.add(key); + Modular.debugPrintModular( + "-- ${module.runtimeType.toString()} DISPOSED"); + } + }); + + for (final key in trash) { + modularRouterDelegate.injectMap.remove(key); + } } return route.didPop(result); diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index cb384491..882d2e27 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -33,6 +33,12 @@ main() { expect(route.child!(context, route.args).toString(), '2'); expect(route.path, '/list/2'); }); + + test('should retrive Widcard router when not exist path', () async { + final route = await parse.selectRoute('/paulo', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + }); }); group('Multi Module | ', () { @@ -151,6 +157,7 @@ class ModuleMock extends ChildModule { text: args?.params!['id'], ), ), + ModularRouter('**', child: (context, args) => FlutterLogo()) ]; } From b34a234663c47ff60cfb7232a8a63281ff9a1b36 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 8 Dec 2020 13:31:18 -0300 Subject: [PATCH 47/71] chage version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 06322d1d..fbd0f25f 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.7 +version: 3.0.0-nullsafety.8 homepage: https://github.com/Flutterando/modular environment: From 0a080c82f2c48fa051ced5ef5935b64c0bf6954b Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 8 Dec 2020 19:56:23 -0300 Subject: [PATCH 48/71] add guards --- .../lib/src/core/interfaces/route_guard.dart | 3 +- .../lib/src/core/modules/child_module.dart | 5 +- .../modular_route_information_parser.dart | 50 ++++++++++++++++--- .../modular_route_information_parse_test.dart | 48 ++++++++++++++++-- 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/flutter_modular/lib/src/core/interfaces/route_guard.dart b/flutter_modular/lib/src/core/interfaces/route_guard.dart index 4ec8e028..1384994c 100644 --- a/flutter_modular/lib/src/core/interfaces/route_guard.dart +++ b/flutter_modular/lib/src/core/interfaces/route_guard.dart @@ -2,6 +2,7 @@ import '../models/modular_router.dart'; -mixin RouteGuard { +// ignore: one_member_abstracts +abstract class RouteGuard { Future canActivate(String path, ModularRouter router); } diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/modules/child_module.dart index 23baded8..f1efb444 100644 --- a/flutter_modular/lib/src/core/modules/child_module.dart +++ b/flutter_modular/lib/src/core/modules/child_module.dart @@ -6,9 +6,10 @@ import '../inject/inject.dart'; import '../interfaces/disposable.dart'; import '../models/modular_router.dart'; +@immutable abstract class ChildModule { - List binds = []; - List routers = []; + late final List binds; + late final List routers; @visibleForTesting void changeBinds(List b) { diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 3bd43fb1..2f89c2d7 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -70,8 +70,8 @@ class ModularRouteInformationParser if (router != null) { router = router.copyWith( - modulePath: router.modulePath == null ? '/' : tempRouteName, - ); + modulePath: router.modulePath == null ? '/' : tempRouteName, + currentModule: route.currentModule); if (router.transition == TransitionType.defaultTransition) { router = router.copyWith( @@ -176,19 +176,53 @@ class ModularRouteInformationParser return router.copyWith(path: routeNamed); } + ModularRouter? _searchWildcard( + String path, + ChildModule module, + ) { + ModularRouter? finded; + + final segments = path.split('/')..removeLast(); + final length = segments.length; + for (var i = 0; i < length; i++) { + final localPath = segments.join('/'); + final route = _searchInModule(module, "", localPath); + if (route != null) { + if (route.children.isNotEmpty && route.routerName != '/') { + finded = route.children.last.routerName == '**' + ? route.children.last + : null; + } else { + finded = route.currentModule?.routers.last.routerName == '**' + ? route.currentModule?.routers.last + : null; + } + route.currentModule?.paths.remove(localPath); + break; + } else { + segments.removeLast(); + } + } + + return finded?.routerName == '**' ? finded : null; + } + Future selectRoute(String path, [ChildModule? module]) async { if (path.isEmpty) { throw Exception("Router can not be empty"); } - var route = _searchInModule(module ?? Modular.initialModule, "", path); - return canActivate(path, route); - } + var router = _searchInModule(module ?? Modular.initialModule, "", path); - Future canActivate(String path, ModularRouter? router) async { - if (router == null) { - throw ModularError('Route \'$path\' not found'); + if (router != null) { + return canActivate(path, router); + } else { + router = _searchWildcard(path, module ?? Modular.initialModule); + if (router != null) return router; } + throw ModularError('Route \'$path\' not found'); + } + Future canActivate(String path, ModularRouter router) async { if (router.guards?.isNotEmpty == true) { for (var guard in router.guards!) { try { diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index 882d2e27..9802f9bb 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -39,6 +39,11 @@ main() { expect(route, isNotNull); expect(route.child!(context, null), isA()); }); + + test('should guard router /401', () async { + expect(parse.selectRoute('/401', ModuleMock()), + throwsA(isA())); + }); }); group('Multi Module | ', () { @@ -69,6 +74,17 @@ main() { expect(route.child!(context, route.args).toString(), '3'); expect(route.path, '/mock/list/3'); }); + + test('should retrive Widcard router when not exist path', () async { + final route = await parse.selectRoute('/mock/paulo', ModuleMock()); + expect(route, isNotNull); + expect(route.child!(context, null), isA()); + }); + + test('should guard router /mock/listguarded', () async { + expect(parse.selectRoute('/mock/listguarded', ModuleMock()), + throwsA(isA())); + }); }); group('Outlet Module | ', () { @@ -117,7 +133,7 @@ main() { class ModuleMock extends ChildModule { @override - List binds = [ + final List binds = [ Bind((i) => "Test"), Bind((i) => true, lazy: false), Bind((i) => StreamController(), lazy: false), @@ -125,7 +141,7 @@ class ModuleMock extends ChildModule { ]; @override - List routers = [ + final List routers = [ ModularRouter( '/', child: (context, args) => Container(), @@ -151,6 +167,11 @@ class ModuleMock extends ChildModule { '/list', child: (context, args) => ListView(), ), + ModularRouter( + '/401', + guards: [MyGuard()], + child: (context, args) => SingleChildScrollView(), + ), ModularRouter( '/list/:id', child: (context, args) => CustomWidget( @@ -163,7 +184,7 @@ class ModuleMock extends ChildModule { class ModuleMock2 extends ChildModule { @override - List binds = [ + final List binds = [ Bind((i) => "Test"), Bind((i) => true, lazy: false), Bind((i) => StreamController(), lazy: false), @@ -171,7 +192,7 @@ class ModuleMock2 extends ChildModule { ]; @override - List routers = [ + final List routers = [ ModularRouter('/', child: (context, args) => SizedBox(), children: [ ModularRouter('/home', child: (context, args) => Container()), ]), @@ -179,12 +200,18 @@ class ModuleMock2 extends ChildModule { '/list', child: (context, args) => ListView(), ), + ModularRouter( + '/listguarded', + guards: [MyGuard()], + child: (context, args) => ListView(), + ), ModularRouter( '/list/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], ), ), + ModularRouter('**', child: (context, args) => FlutterLogo()) ]; } @@ -203,3 +230,16 @@ class CustomWidget extends StatelessWidget { return text; } } + +class MyGuard implements RouteGuard { + @override + Future canActivate(String path, ModularRouter router) async { + if (path == '/401') { + return false; + } else if (path == '/mock/listguarded') { + return false; + } else { + return true; + } + } +} From 6db9609d5e2d4075112d1a934dc8c4169c56d12f Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 8 Dec 2020 20:21:19 -0300 Subject: [PATCH 49/71] guard module --- .../modular_route_information_parser.dart | 9 ++- .../modular_route_information_parse_test.dart | 56 +++++++++++++++++-- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 2f89c2d7..622f39de 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -70,8 +70,13 @@ class ModularRouteInformationParser if (router != null) { router = router.copyWith( - modulePath: router.modulePath == null ? '/' : tempRouteName, - currentModule: route.currentModule); + modulePath: router.modulePath == null ? '/' : tempRouteName, + currentModule: route.currentModule, + guards: [ + if (route.guards != null) ...route.guards!, + if (router.guards != null) ...router.guards! + ], + ); if (router.transition == TransitionType.defaultTransition) { router = router.copyWith( diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index 9802f9bb..5373d145 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -85,6 +85,11 @@ main() { expect(parse.selectRoute('/mock/listguarded', ModuleMock()), throwsA(isA())); }); + + test('should guard router /guarded/list', () async { + expect(parse.selectRoute('/guarded/list', ModuleMock()), + throwsA(isA())); + }); }); group('Outlet Module | ', () { @@ -159,18 +164,47 @@ class ModuleMock extends ChildModule { ), ], ), + ModularRouter('/mock', module: ModuleMock2()), + ModularRouter('/guarded', + guards: [MyGuardModule()], module: ModuleGuarded()), + ModularRouter('/list', child: (context, args) => ListView()), ModularRouter( - '/mock', - module: ModuleMock2(), + '/401', + guards: [MyGuard()], + child: (context, args) => SingleChildScrollView(), + ), + ModularRouter( + '/list/:id', + child: (context, args) => CustomWidget( + text: args?.params!['id'], + ), ), + ModularRouter('**', child: (context, args) => FlutterLogo()) + ]; +} + +class ModuleMock2 extends ChildModule { + @override + final List binds = [ + Bind((i) => "Test"), + Bind((i) => true, lazy: false), + Bind((i) => StreamController(), lazy: false), + Bind((i) => ValueNotifier(0), lazy: false), + ]; + + @override + final List routers = [ + ModularRouter('/', child: (context, args) => SizedBox(), children: [ + ModularRouter('/home', child: (context, args) => Container()), + ]), ModularRouter( '/list', child: (context, args) => ListView(), ), ModularRouter( - '/401', + '/listguarded', guards: [MyGuard()], - child: (context, args) => SingleChildScrollView(), + child: (context, args) => ListView(), ), ModularRouter( '/list/:id', @@ -182,7 +216,7 @@ class ModuleMock extends ChildModule { ]; } -class ModuleMock2 extends ChildModule { +class ModuleGuarded extends ChildModule { @override final List binds = [ Bind((i) => "Test"), @@ -195,6 +229,7 @@ class ModuleMock2 extends ChildModule { final List routers = [ ModularRouter('/', child: (context, args) => SizedBox(), children: [ ModularRouter('/home', child: (context, args) => Container()), + ModularRouter('/guarded', child: (context, args) => Container()), ]), ModularRouter( '/list', @@ -243,3 +278,14 @@ class MyGuard implements RouteGuard { } } } + +class MyGuardModule implements RouteGuard { + @override + Future canActivate(String path, ModularRouter router) async { + if (path == '/guarded/list') { + return false; + } else { + return true; + } + } +} From 8aa2fbe005f36c4107be0a746bd7f991007b8f51 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 9 Dec 2020 17:29:49 -0300 Subject: [PATCH 50/71] implemented Relative Router --- .../modular_navigator_interface.dart | 20 ++++---- .../navigation/custom_navigator.dart | 48 +++++++++++++++++++ .../modular_route_information_parser.dart | 6 ++- .../navigation/modular_router_delegate.dart | 34 ++++++++++--- .../navigation/router_outlet_delegate.dart | 3 +- .../modular_route_delegate_test.dart | 15 ++++++ .../modular_route_information_parse_test.dart | 2 + 7 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 flutter_modular/lib/src/presenters/navigation/custom_navigator.dart create mode 100644 flutter_modular/test/src/presenters/navigation/modular_route_delegate_test.dart diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart index 8cef7218..d756fbb1 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart +++ b/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart @@ -24,10 +24,10 @@ abstract class IModularNavigator { /// ``` /// Modular.to.popAndPushNamed('/home', arguments: 10); /// ``` - Future popAndPushNamed( + Future popAndPushNamed( String routeName, - {TO result, - Object arguments, + {TO? result, + Object? arguments, bool forRoot = false}); /// Navigate to a route. @@ -39,8 +39,8 @@ abstract class IModularNavigator { /// ``` /// Modular.to.pushNamed('/home', arguments: 10); /// ``` - Future pushNamed(String routeName, - {Object arguments, bool forRoot = false}); + Future pushNamed(String routeName, + {Object? arguments, bool forRoot = false}); /// Push the route with the given name onto the navigator that most tightly /// encloses the given context, and then remove all the previous routes until @@ -53,9 +53,9 @@ abstract class IModularNavigator { /// ``` /// Modular.to.pushNamedAndRemoveUntil('/home', ModalRoute.withName('/'), arguments: 10); /// ``` - Future pushNamedAndRemoveUntil( + Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, - {Object arguments, bool forRoot = false}); + {Object? arguments, bool forRoot = false}); ///Replace the current route of the navigator that most tightly encloses the ///given context by pushing the route named routeName and then disposing the @@ -68,10 +68,10 @@ abstract class IModularNavigator { /// ``` /// Modular.to.pushReplacementNamed('/home', arguments: 10); /// ``` - Future pushReplacementNamed( + Future pushReplacementNamed( String routeName, - {TO result, - Object arguments, + {TO? result, + Object? arguments, bool forRoot = false}); /// Removes the current Route from the stack of routes. diff --git a/flutter_modular/lib/src/presenters/navigation/custom_navigator.dart b/flutter_modular/lib/src/presenters/navigation/custom_navigator.dart new file mode 100644 index 00000000..3c8bcf9d --- /dev/null +++ b/flutter_modular/lib/src/presenters/navigation/custom_navigator.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +import '../modular_base.dart'; + +class CustomNavigator extends Navigator { + CustomNavigator({ + Key? key, + List> pages = const >[], + bool Function(Route, dynamic)? onPopPage, + }) : super(key: key, pages: pages, onPopPage: onPopPage); + + @override + _CustomNavigatorState createState() => _CustomNavigatorState(); +} + +class _CustomNavigatorState extends NavigatorState { + @override + Future pushNamed(String routeName, + {Object? arguments}) { + return Modular.to.pushNamed(routeName, arguments: arguments); + } + + @override + Future popAndPushNamed( + String routeName, + {TO? result, + Object? arguments}) { + return Modular.to.popAndPushNamed(routeName, + result: result, arguments: arguments); + } + + @override + Future pushNamedAndRemoveUntil( + String newRouteName, predicate, + {Object? arguments}) { + return Modular.to.pushNamedAndRemoveUntil(newRouteName, predicate, + arguments: arguments); + } + + @override + Future pushReplacementNamed( + String routeName, + {TO? result, + Object? arguments}) { + return Modular.to.pushReplacementNamed(routeName, + result: result, arguments: arguments); + } +} diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 622f39de..524560c5 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -94,10 +94,12 @@ class ModularRouteInformationParser for (var routeChild in route.children) { var r = _searchRoute(routeChild, tempRouteName, path); if (r != null) { + r.currentModule?.paths.remove(path); route = route.copyWith(routerOutlet: [ r.copyWith( - modulePath: resolveOutletModulePath( - tempRouteName, r.modulePath ?? '/')) + modulePath: r.modulePath == route.modulePath + ? tempRouteName + : r.modulePath), ], path: tempRouteName); return route; } diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index c52bf6d4..aa6609dd 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -5,6 +5,7 @@ import '../../core/models/modular_router.dart'; import '../../core/modules/child_module.dart'; import '../interfaces/modular_navigator_interface.dart'; import '../modular_base.dart'; +import 'custom_navigator.dart'; import 'modular_page.dart'; import 'modular_route_information_parser.dart'; @@ -40,7 +41,7 @@ class ModularRouterDelegate extends RouterDelegate Widget build(BuildContext context) { return _pages.isEmpty ? Material() - : Navigator( + : CustomNavigator( key: navigatorKey, pages: _pages, onPopPage: _onPopPage, @@ -59,7 +60,12 @@ class ModularRouterDelegate extends RouterDelegate } else { for (var p in _pages) { p.completePop(null); + removeInject(p.router.path!); + for (var r in p.router.routerOutlet) { + removeInject(r.path!); + } } + _pages = [page]; } @@ -68,12 +74,20 @@ class ModularRouterDelegate extends RouterDelegate } } + String resolverPath(String routeName, String path) { + final uri = Uri.parse(path); + return uri.resolve(routeName).path; + } + @override Future navigate(String routeName, {arguments, bool linked = false}) async { if (routeName == path) { return; } + + routeName = resolverPath(routeName, path); + var router = await parser.selectRoute(linked ? modulePath + routeName : routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); @@ -114,6 +128,9 @@ class ModularRouterDelegate extends RouterDelegate injectMap.forEach((key, module) { module.paths.remove(path); + if (path.characters.last == '/') { + module.paths.remove('$path/'.replaceAll('//', '')); + } if (module.paths.length == 0) { module.cleanInjects(); trash.add(key); @@ -133,8 +150,9 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future pushNamed(String routeName, + Future pushNamed(String routeName, {Object? arguments, bool forRoot = false}) async { + routeName = resolverPath(routeName, path); var router = await parser.selectRoute(routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); @@ -153,7 +171,7 @@ class ModularRouterDelegate extends RouterDelegate return await page.waitPop(); } else { routerOutlatPages[router.path!]?.add(page); - currentConfiguration?.routerOutlet.add(router); + currentConfiguration?.routerOutlet.add(outletRouter); notifyListeners(); final result = await page.waitPop(); routerOutlatPages[router.path!]?.removeLast(); @@ -173,11 +191,12 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future pushReplacementNamed( + Future pushReplacementNamed( String routeName, {TO? result, Object? arguments, bool forRoot = false}) async { + routeName = resolverPath(routeName, path); var router = await parser.selectRoute(routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); @@ -200,7 +219,7 @@ class ModularRouterDelegate extends RouterDelegate } else { final lastPage = routerOutlatPages[router.path!]?.last; routerOutlatPages[router.path!]?.last = page; - currentConfiguration?.routerOutlet.last = router; + currentConfiguration?.routerOutlet.last = outletRouter; notifyListeners(); final result = await page.waitPop(); lastPage!.completePop(result); @@ -223,11 +242,12 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future popAndPushNamed( + Future popAndPushNamed( String routeName, {TO? result, Object? arguments, bool forRoot = false}) async { + routeName = resolverPath(routeName, path); var router = await parser.selectRoute(routeName); if (!forRoot && router.routerOutlet.isNotEmpty) { routerOutlatPages[router.path!]?.last.completePop(result); @@ -257,7 +277,7 @@ class ModularRouterDelegate extends RouterDelegate navigator.popUntil(predicate); @override - Future pushNamedAndRemoveUntil( + Future pushNamedAndRemoveUntil( String newRouteName, bool Function(Route) predicate, {Object? arguments, bool forRoot = false}) { popUntil(predicate); diff --git a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart index d43f5fc6..9baf69ca 100644 --- a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import '../../core/models/modular_router.dart'; import '../modular_base.dart'; +import 'custom_navigator.dart'; import 'modular_page.dart'; import 'modular_router_delegate.dart'; @@ -39,7 +40,7 @@ class RouterOutletDelegate extends RouterDelegate Widget build(BuildContext context) { return pages.isEmpty ? Material() - : Navigator( + : CustomNavigator( pages: _getPages(), onPopPage: (route, result) { if (pages.length > 1) { diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_delegate_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_delegate_test.dart new file mode 100644 index 00000000..9ca10085 --- /dev/null +++ b/flutter_modular/test/src/presenters/navigation/modular_route_delegate_test.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/presenters/navigation/modular_route_information_parser.dart'; +import 'package:flutter_modular/src/presenters/navigation/modular_router_delegate.dart'; +import 'package:flutter_test/flutter_test.dart'; + +main() { + WidgetsFlutterBinding.ensureInitialized(); + + final delegate = ModularRouterDelegate(ModularRouteInformationParser(), {}); + + test('should resolve relative path', () { + expect(delegate.resolverPath('tab2', '/home/tab1'), '/home/tab2'); + expect(delegate.resolverPath('../tab2', '/home/tab1/test'), '/home/tab2'); + }); +} diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index 5373d145..ebb5a9fc 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -133,6 +133,8 @@ main() { test('should resolve Outlet Module Path', () async { expect(parse.resolveOutletModulePath('/home', '/'), '/home'); + expect( + parse.resolveOutletModulePath('/home/', '/home/start'), '/home/start'); }); } From 33ec25b20610383837332ab9222104613d8cad75 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 9 Dec 2020 17:52:10 -0300 Subject: [PATCH 51/71] change modularRouter to ModularRoute --- .../modular_route_information_parser.dart | 26 +- .../delegates/modular_router_delegate.dart | 14 +- .../.src/interfaces/child_module.dart | 2 +- .../.src/interfaces/route_guard.dart | 2 +- flutter_modular/.src/modular_base.dart | 2 +- flutter_modular/.src/modular_impl.dart | 2 +- .../.src/routers/modular_link.dart | 2 +- .../.src/routers/modular_page.dart | 2 +- .../.src/routers/modular_router.dart | 20 +- .../.src/widgets/widget_module.dart | 4 +- flutter_modular/README.md | 52 +-- flutter_modular/lib/flutter_modular.dart | 2 +- .../lib/src/core/interfaces/route_guard.dart | 4 +- .../lib/src/core/models/modular_route.dart | 298 ++++++++++++++++++ .../lib/src/core/models/modular_router.dart | 20 +- .../lib/src/core/modules/child_module.dart | 4 +- .../presenters/navigation/modular_page.dart | 8 +- .../modular_route_information_parser.dart | 32 +- .../navigation/modular_router_delegate.dart | 10 +- .../navigation/router_outlet_delegate.dart | 8 +- .../src/presenters/widgets/widget_module.dart | 6 +- .../src/core/models/modular_router_test.dart | 14 +- .../src/core/modules/child_module_test.dart | 4 +- .../modular_route_information_parse_test.dart | 56 ++-- 24 files changed, 446 insertions(+), 148 deletions(-) create mode 100644 flutter_modular/lib/src/core/models/modular_route.dart diff --git a/flutter_modular/.src/delegates/modular_route_information_parser.dart b/flutter_modular/.src/delegates/modular_route_information_parser.dart index 42953ed1..2bbb812b 100644 --- a/flutter_modular/.src/delegates/modular_route_information_parser.dart +++ b/flutter_modular/.src/delegates/modular_route_information_parser.dart @@ -3,9 +3,9 @@ import 'package:flutter/material.dart'; import '../../flutter_modular.dart'; class ModularRouteInformationParser - extends RouteInformationParser { + extends RouteInformationParser { @override - Future parseRouteInformation( + Future parseRouteInformation( RouteInformation routeInformation) async { final path = routeInformation.location ?? '/'; final route = await selectRoute(path); @@ -13,11 +13,11 @@ class ModularRouteInformationParser } @override - RouteInformation restoreRouteInformation(ModularRouter router) { + RouteInformation restoreRouteInformation(ModularRoute router) { return RouteInformation(location: router.path); } - ModularRouter? _searchInModule( + ModularRoute? _searchInModule( ChildModule module, String routerName, String path) { path = "/$path".replaceAll('//', '/'); final routers = @@ -34,9 +34,9 @@ class ModularRouteInformationParser return null; } - ModularRouter? _normalizeRoute( - ModularRouter route, String routerName, String path) { - ModularRouter? router; + ModularRoute? _normalizeRoute( + ModularRoute route, String routerName, String path) { + ModularRoute? router; if (routerName == path || routerName == "$path/") { router = route.module!.routers[0]; if (router.module != null) { @@ -50,8 +50,8 @@ class ModularRouteInformationParser return router; } - ModularRouter? _searchRoute( - ModularRouter route, String routerName, String path) { + ModularRoute? _searchRoute( + ModularRoute route, String routerName, String path) { final tempRouteName = (routerName + route.routerName).replaceFirst('//', '/'); if (route.child == null) { @@ -105,8 +105,8 @@ class ModularRouteInformationParser return newUrl.join("/"); } - ModularRouter _parseUrlParams( - ModularRouter router, String routeNamed, String path) { + ModularRoute _parseUrlParams( + ModularRoute router, String routeNamed, String path) { if (routeNamed.contains('/:')) { final regExp = RegExp( "^${prepareToRegex(routeNamed)}\$", @@ -147,7 +147,7 @@ class ModularRouteInformationParser return router; } - Future selectRoute(String path, [ChildModule? module]) async { + Future selectRoute(String path, [ChildModule? module]) async { if (path.isEmpty) { throw Exception("Router can not be empty"); } @@ -155,7 +155,7 @@ class ModularRouteInformationParser return canActivate(path, route); } - Future canActivate(String path, ModularRouter? router) async { + Future canActivate(String path, ModularRoute? router) async { if (router == null) { throw ModularError('Route not found'); } diff --git a/flutter_modular/.src/delegates/modular_router_delegate.dart b/flutter_modular/.src/delegates/modular_router_delegate.dart index 62eaa047..85412e46 100644 --- a/flutter_modular/.src/delegates/modular_router_delegate.dart +++ b/flutter_modular/.src/delegates/modular_router_delegate.dart @@ -4,28 +4,28 @@ import '../routers/modular_page.dart'; import 'modular_route_information_parser.dart'; -class ModularRouterDelegate extends RouterDelegate +class ModularRouteDelegate extends RouterDelegate with // ignore: prefer_mixin ChangeNotifier, - PopNavigatorRouterDelegateMixin + PopNavigatorRouterDelegateMixin implements IModularNavigator { final GlobalKey navigatorKey; final ModularRouteInformationParser parser; final Map injectMap; - ModularRouterDelegate(this.navigatorKey, this.parser, this.injectMap); + ModularRouteDelegate(this.navigatorKey, this.parser, this.injectMap); NavigatorState get navigator => navigatorKey.currentState!; - ModularRouter? _router; + ModularRoute? _router; List _pages = []; @override - ModularRouter? get currentConfiguration => _router; - ModularRouter get lastPage => _pages.last.router; + ModularRoute? get currentConfiguration => _router; + ModularRoute get lastPage => _pages.last.router; @override Widget build(BuildContext context) { @@ -39,7 +39,7 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future setNewRoutePath(ModularRouter router) async { + Future setNewRoutePath(ModularRoute router) async { final page = ModularPage( key: ValueKey('url:${router.path}'), router: router, diff --git a/flutter_modular/.src/interfaces/child_module.dart b/flutter_modular/.src/interfaces/child_module.dart index 3f2705e3..6d108dbe 100644 --- a/flutter_modular/.src/interfaces/child_module.dart +++ b/flutter_modular/.src/interfaces/child_module.dart @@ -6,7 +6,7 @@ import '../routers/modular_router.dart'; abstract class ChildModule { late List _binds; List get binds; - List get routers; + List get routers; ChildModule() { _binds = binds; diff --git a/flutter_modular/.src/interfaces/route_guard.dart b/flutter_modular/.src/interfaces/route_guard.dart index a831ca51..e36f79f5 100644 --- a/flutter_modular/.src/interfaces/route_guard.dart +++ b/flutter_modular/.src/interfaces/route_guard.dart @@ -2,5 +2,5 @@ import '../routers/modular_router.dart'; mixin RouteGuard { - Future canActivate(String path, ModularRouter router); + Future canActivate(String path, ModularRoute router); } diff --git a/flutter_modular/.src/modular_base.dart b/flutter_modular/.src/modular_base.dart index 24a713cf..5b9393e9 100644 --- a/flutter_modular/.src/modular_base.dart +++ b/flutter_modular/.src/modular_base.dart @@ -12,7 +12,7 @@ final _navigatorKey = GlobalKey(); final Map _injectMap = {}; final _routeInformationParser = ModularRouteInformationParser(); -final _routerDelegate = ModularRouterDelegate( +final _routerDelegate = ModularRouteDelegate( _navigatorKey, _routeInformationParser, _injectMap, diff --git a/flutter_modular/.src/modular_impl.dart b/flutter_modular/.src/modular_impl.dart index da3ebf95..ece5da30 100644 --- a/flutter_modular/.src/modular_impl.dart +++ b/flutter_modular/.src/modular_impl.dart @@ -7,7 +7,7 @@ import 'interfaces/modular_interface.dart'; late ChildModule _initialModule; class ModularImpl implements ModularInterface { - final ModularRouterDelegate routerDelegate; + final ModularRouteDelegate routerDelegate; final Map injectMap; IModularNavigator? navigatorDelegate; diff --git a/flutter_modular/.src/routers/modular_link.dart b/flutter_modular/.src/routers/modular_link.dart index fcca63d5..7a6f4301 100644 --- a/flutter_modular/.src/routers/modular_link.dart +++ b/flutter_modular/.src/routers/modular_link.dart @@ -3,7 +3,7 @@ import '../delegates/modular_router_delegate.dart'; import '../interfaces/modular_navigator_interface.dart'; class ModularLink implements IModularNavigator { - final ModularRouterDelegate delegate; + final ModularRouteDelegate delegate; ModularLink(this.delegate); diff --git a/flutter_modular/.src/routers/modular_page.dart b/flutter_modular/.src/routers/modular_page.dart index 62b26b83..5d079589 100644 --- a/flutter_modular/.src/routers/modular_page.dart +++ b/flutter_modular/.src/routers/modular_page.dart @@ -7,7 +7,7 @@ import '../../flutter_modular.dart'; final Map _allCompleters = {}; class ModularPage extends Page { - final ModularRouter router; + final ModularRoute router; ModularPage({LocalKey? key, required this.router}) : super(key: key, name: router.path, arguments: router.args?.data); diff --git a/flutter_modular/.src/routers/modular_router.dart b/flutter_modular/.src/routers/modular_router.dart index 28dcfe12..af4661d7 100644 --- a/flutter_modular/.src/routers/modular_router.dart +++ b/flutter_modular/.src/routers/modular_router.dart @@ -14,12 +14,12 @@ typedef RouteBuilder = MaterialPageRoute Function( typedef ModularChild = Widget Function( BuildContext context, ModularArguments? args); -class ModularRouter { +class ModularRoute { final ChildModule? currentModule; final ModularArguments? args; - final List children; + final List children; final String? path; @@ -83,7 +83,7 @@ class ModularRouter { /// ```dart ///class MyGuard implements RouteGuard { /// @override - /// Future canActivate(String url, ModularRouter router) { + /// Future canActivate(String url, ModularRoute router) { /// if (url != '/admin'){ /// // Return `true` to allow access /// return true; @@ -190,7 +190,7 @@ class ModularRouter { TransitionType.leftToRightWithFade: leftToRightWithFade, }; - ModularRouter( + ModularRoute( this.routerName, { this.path = '/', this.children = const [], @@ -213,11 +213,11 @@ class ModularRouter { assert(module == null ? true : children.isEmpty, 'Módulo não pode conter rotas aninhadas (children)'); - ModularRouter copyWith( + ModularRoute copyWith( {ModularChild? child, String? routerName, ChildModule? module, - List? children, + List? children, ChildModule? currentModule, Map? params, List? guards, @@ -229,7 +229,7 @@ class ModularRouter { Completer? popRoute, ModularArguments? args, CustomTransition? customTransition}) { - return ModularRouter( + return ModularRoute( routerName ?? this.routerName, child: child ?? this.child, args: args ?? this.args, @@ -247,8 +247,8 @@ class ModularRouter { ); } - static List group({ - required List routes, + static List group({ + required List routes, List? guards, TransitionType? transition, CustomTransition? customTransition, @@ -305,7 +305,7 @@ class ModularRouter { bool operator ==(Object o) { if (identical(this, o)) return true; - return o is ModularRouter && + return o is ModularRoute && o.modulePath == modulePath && o.routerName == routerName && o.module == module; diff --git a/flutter_modular/.src/widgets/widget_module.dart b/flutter_modular/.src/widgets/widget_module.dart index 5a8f0b11..2b2cdf08 100644 --- a/flutter_modular/.src/widgets/widget_module.dart +++ b/flutter_modular/.src/widgets/widget_module.dart @@ -49,7 +49,7 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { } @override - List get routers => const []; + List get routers => const []; @override Widget build(BuildContext context) { @@ -71,7 +71,7 @@ class _FakeModule extends ChildModule { List get binds => bindsInject ?? []; @override - List get routers => []; + List get routers => []; } class ModularProvider extends StatefulWidget { diff --git a/flutter_modular/README.md b/flutter_modular/README.md index a31c65fd..8b6199ce 100644 --- a/flutter_modular/README.md +++ b/flutter_modular/README.md @@ -128,7 +128,7 @@ class AppModule extends MainModule { // Provide all the routes for your module @override - List get routers => []; + List get routers => []; // Provide the root widget associated with your module // In this case, it's the widget you created in the first step @@ -165,9 +165,9 @@ class AppModule extends MainModule { // Provide all the routes for your module @override - List get routers => [ - ModularRouter('/', child: (_, __) => HomePage()), - ModularRouter('/login', child: (_, __) => LoginPage()), + List get routers => [ + ModularRoute('/', child: (_, __) => HomePage()), + ModularRoute('/login', child: (_, __) => LoginPage()), ]; // Provide the root widget associated with your module @@ -213,8 +213,8 @@ You can use the dynamic routing system to provide parameters to your `Router`: // using square brackets notation (['parameter_name']). @override -List get routers => [ - ModularRouter( +List get routers => [ + ModularRoute( '/product/:id', child: (_, args) => Product(id: args.params['id']), ), @@ -238,8 +238,8 @@ And it will be available in the `args.data` property instead of `args.params`: ```dart @override -List get routers => [ - ModularRouter( +List get routers => [ + ModularRoute( '/product', child: (_, args) => Product(model: args.data), ), @@ -271,9 +271,9 @@ To use your `RouteGuard` in a route, pass it to the `guards` parameter: ```dart @override -List get routers => [ - ModularRouter('/', module: HomeModule()), - ModularRouter( +List get routers => [ + ModularRoute('/', module: HomeModule()), + ModularRoute( '/admin', module: AdminModule(), guards: [MyGuard()], @@ -289,7 +289,7 @@ If placed on a module route, `RouterGuard` will be global to that route. You can choose which type of animation you want to be used on your pages transition by setting the `Router`'s `transition` parameter, providing a `TransitionType`. ```dart -ModularRouter('/product', +ModularRoute('/product', module: AdminModule(), transition: TransitionType.fadeIn, ), //use for change transition @@ -302,7 +302,7 @@ If you use transition in a module, all routes in that module will inherit this t You can also use a custom transition animation by setting the Router parameters `transition` and `customTransition` with `TransitionType.custom` and your `CustomTransition`, respectively: ```dart -ModularRouter('/product', +ModularRoute('/product', module: AdminModule(), transition: TransitionType.custom, customTransition: myCustomTransition, @@ -351,13 +351,13 @@ CustomTransition get myCustomTransition => CustomTransition( You can group routes that contains one or more common properties. Properties like `guards`, `transition` and `customTransition` can be provided both for single routes and groups of routes: ```dart -List get routers => [ - ModularRouter('/', module: HomeModule()), +List get routers => [ + ModularRoute('/', module: HomeModule()), Router.group( guards: [MyGuard()], routes: [ - ModularRouter("/admin", module: AdminModule()), - ModularRouter("/profile", module: ProfileModule()), + ModularRoute("/admin", module: AdminModule()), + ModularRoute("/profile", module: ProfileModule()), ], ), ); @@ -370,7 +370,7 @@ To achieve this, pass the type you expect to return as type parameter to `Router ```dart @override -List get routers => [ +List get routers => [ // This router expects to receive a `String` when popped. Router('/event', child: (_, __) => EventPage()), ] @@ -413,9 +413,9 @@ class AppModule extends MainModule { // Provide all the routes for your module @override - List get routers => [ - ModularRouter('/', child: (_, args) => HomePage()), - ModularRouter('/login', child: (_, args) => LoginPage()), + List get routers => [ + ModularRoute('/', child: (_, args) => HomePage()), + ModularRoute('/login', child: (_, args) => LoginPage()), ]; // Provide the root widget associated with your module @@ -557,9 +557,9 @@ class HomeModule extends ChildModule { ]; @override - List get routers => [ - ModularRouter('/', child: (_, args) => HomeWidget()), - ModularRouter('/list', child: (_, args) => ListWidget()), + List get routers => [ + ModularRoute('/', child: (_, args) => HomeWidget()), + ModularRoute('/list', child: (_, args) => ListWidget()), ]; static Inject get to => Inject.of(); @@ -572,8 +572,8 @@ You may then pass the submodule to a `Router` in your main module through the `m class AppModule extends MainModule { @override - List get routers => [ - ModularRouter('/home', module: HomeModule()), + List get routers => [ + ModularRoute('/home', module: HomeModule()), ]; } ``` diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index e9798a52..b618418a 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -6,7 +6,7 @@ export 'src/core/inject/inject.dart'; export 'src/core/interfaces/disposable.dart'; export 'src/core/interfaces/route_guard.dart'; export 'src/core/models/modular_arguments.dart'; -export 'src/core/models/modular_router.dart'; +export 'src/core/models/modular_route.dart'; export 'src/core/modules/child_module.dart'; export 'src/core/modules/main_module.dart'; export 'src/presenters/modular_base.dart'; diff --git a/flutter_modular/lib/src/core/interfaces/route_guard.dart b/flutter_modular/lib/src/core/interfaces/route_guard.dart index 1384994c..fea976e4 100644 --- a/flutter_modular/lib/src/core/interfaces/route_guard.dart +++ b/flutter_modular/lib/src/core/interfaces/route_guard.dart @@ -1,8 +1,8 @@ //ignore:one_member_abstracts -import '../models/modular_router.dart'; +import '../models/modular_route.dart'; // ignore: one_member_abstracts abstract class RouteGuard { - Future canActivate(String path, ModularRouter router); + Future canActivate(String path, ModularRoute router); } diff --git a/flutter_modular/lib/src/core/models/modular_route.dart b/flutter_modular/lib/src/core/models/modular_route.dart new file mode 100644 index 00000000..4ec97168 --- /dev/null +++ b/flutter_modular/lib/src/core/models/modular_route.dart @@ -0,0 +1,298 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../interfaces/route_guard.dart'; +import '../modules/child_module.dart'; +import '../transitions/transitions.dart'; +import 'modular_arguments.dart'; + +typedef RouteBuilder = MaterialPageRoute Function( + WidgetBuilder, RouteSettings); +typedef ModularChild = Widget Function( + BuildContext context, ModularArguments? args); + +class ModularRoute { + final ChildModule? currentModule; + + final ModularArguments? args; + + final List children; + + final List routerOutlet; + + final String? path; + + /// + /// Paramenter name: [routerName] + /// + /// Name for your route + /// + /// Type: String + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final String routerName; + + /// + /// Paramenter name: [child] + /// + /// The widget will be displayed + /// + /// Type: Widget + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + + final ModularChild? child; + + /// + /// Paramenter name: [module] + /// + /// The module will be loaded + /// + /// Type: ChildModule + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final ChildModule? module; + + /// + /// Paramenter name: [params] + /// + /// The parameters that can be transferred to another screen + /// + /// Type: Map + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final Map? params; + + /// + /// Paramenter name: [guards] + /// + /// Route guards are middleware-like objects + /// + /// that allow you to control the access of a given route from other route. + /// + /// You can implement a route guard by making a class that implements RouteGuard. + /// + /// Type: List + /// + /// Example: + /// ```dart + ///class MyGuard implements RouteGuard { + /// @override + /// Future canActivate(String url, ModularRoute router) { + /// if (url != '/admin'){ + /// // Return `true` to allow access + /// return true; + /// } else { + /// // Return `false` to disallow access + /// return false + /// } + /// } + ///} + /// ``` + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + + final List? guards; + + /// + /// Paramenter name: [transition] + /// + /// Used to animate the transition from one screen to another + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final TransitionType transition; + + /// + /// Paramenter name: [customTransiton] + /// + /// PS: For [customTransition] to work, + /// + /// you must set the [transition] parameter for + /// ```dart + /// transition.custom, + /// ``` + /// + /// Example: Using just First Animation + /// ```dart + /// customTransition: CustomTransition( + /// transitionBuilder: (context, animation, secondaryAnimation, child) { + /// return SlideTransition( + /// transformHitTests: false, + /// position: Tween( + /// begin: const Offset(0.0, 1.0), + /// end: Offset.zero, + /// ).chain(CurveTween(curve: Curves.ease)).animate(animation), + /// child: child); + /// }, + /// ), + /// ``` + + /// Example: Using just secondaryAnimation + /// ```dart + /// customTransition: CustomTransition( + /// transitionBuilder: (context, animation, secondaryAnimation, child) { + /// return SlideTransition( + /// transformHitTests: false, + /// position: Tween( + /// begin: const Offset(0.0, 1.0), + /// end: Offset.zero, + /// ).chain(CurveTween(curve: Curves.ease)).animate(animation), + /// child: SlideTransition( + /// transformHitTests: false, + /// position: Tween( + /// begin: Offset.zero, + /// end: const Offset(0.0, -1.0), + /// ).chain(CurveTween(curve: Curves.ease)).animate(secondaryAnimation), + /// child: child, + /// ), + /// ); + /// }, + /// ), + /// ``` + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final CustomTransition? customTransition; + + /// + /// Paramenter name: [transition] + /// + /// Used to animate the transition from one screen to another + /// + /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] + /// + final RouteBuilder? routeGenerator; + final String? modulePath; + final Duration duration; + final Map< + TransitionType, + PageRouteBuilder Function( + Widget Function(BuildContext, ModularArguments?) builder, + ModularArguments? args, + Duration transitionDuration, + RouteSettings settings, + )> transitions = { + TransitionType.fadeIn: fadeInTransition, + TransitionType.noTransition: noTransition, + TransitionType.rightToLeft: rightToLeft, + TransitionType.leftToRight: leftToRight, + TransitionType.upToDown: upToDown, + TransitionType.downToUp: downToUp, + TransitionType.scale: scale, + TransitionType.rotate: rotate, + TransitionType.size: size, + TransitionType.rightToLeftWithFade: rightToLeftWithFade, + TransitionType.leftToRightWithFade: leftToRightWithFade, + }; + + ModularRoute( + this.routerName, { + this.path = '/', + this.children = const [], + this.args = const ModularArguments(), + this.module, + this.child, + this.guards, + this.routerOutlet = const [], + this.params, + this.currentModule, + this.transition = TransitionType.defaultTransition, + this.routeGenerator, + this.customTransition, + this.duration = const Duration(milliseconds: 300), + this.modulePath = '/', + }) : assert(module == null ? true : children.isEmpty, + 'Módulo não pode conter rotas aninhadas (children)'), + assert((transition == TransitionType.custom && + customTransition != null) || + transition != TransitionType.custom && customTransition == null), + assert((module == null && child != null) || + (module != null && child == null)), + assert(routerName == '**' ? child != null : true); + + ModularRoute copyWith( + {ModularChild? child, + String? routerName, + ChildModule? module, + List? children, + List? routerOutlet, + ChildModule? currentModule, + Map? params, + List? guards, + TransitionType? transition, + RouteBuilder? routeGenerator, + String? modulePath, + String? path, + Duration? duration, + Completer? popRoute, + ModularArguments? args, + CustomTransition? customTransition}) { + return ModularRoute( + routerName ?? this.routerName, + child: child ?? this.child, + args: args ?? this.args, + children: children ?? this.children, + module: module ?? this.module, + routerOutlet: routerOutlet ?? this.routerOutlet, + currentModule: currentModule ?? this.currentModule, + params: params ?? this.params, + modulePath: modulePath ?? this.modulePath, + path: path ?? this.path, + guards: guards ?? this.guards, + duration: duration ?? this.duration, + routeGenerator: routeGenerator ?? this.routeGenerator, + transition: transition ?? this.transition, + customTransition: customTransition ?? this.customTransition, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object o) { + if (identical(this, o)) return true; + + return o is ModularRoute && + o.modulePath == modulePath && + o.routerName == routerName && + o.module == module; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return currentModule.hashCode ^ routerName.hashCode; + } +} + +enum TransitionType { + defaultTransition, + fadeIn, + noTransition, + rightToLeft, + leftToRight, + upToDown, + downToUp, + scale, + rotate, + size, + rightToLeftWithFade, + leftToRightWithFade, + custom, +} + +class CustomTransition { + final Widget Function( + BuildContext, Animation, Animation, Widget) + transitionBuilder; + final Duration transitionDuration; + + CustomTransition( + {required this.transitionBuilder, + this.transitionDuration = const Duration(milliseconds: 300)}); +} diff --git a/flutter_modular/lib/src/core/models/modular_router.dart b/flutter_modular/lib/src/core/models/modular_router.dart index 0532770b..4ec97168 100644 --- a/flutter_modular/lib/src/core/models/modular_router.dart +++ b/flutter_modular/lib/src/core/models/modular_router.dart @@ -13,14 +13,14 @@ typedef RouteBuilder = MaterialPageRoute Function( typedef ModularChild = Widget Function( BuildContext context, ModularArguments? args); -class ModularRouter { +class ModularRoute { final ChildModule? currentModule; final ModularArguments? args; - final List children; + final List children; - final List routerOutlet; + final List routerOutlet; final String? path; @@ -84,7 +84,7 @@ class ModularRouter { /// ```dart ///class MyGuard implements RouteGuard { /// @override - /// Future canActivate(String url, ModularRouter router) { + /// Future canActivate(String url, ModularRoute router) { /// if (url != '/admin'){ /// // Return `true` to allow access /// return true; @@ -191,7 +191,7 @@ class ModularRouter { TransitionType.leftToRightWithFade: leftToRightWithFade, }; - ModularRouter( + ModularRoute( this.routerName, { this.path = '/', this.children = const [], @@ -216,12 +216,12 @@ class ModularRouter { (module != null && child == null)), assert(routerName == '**' ? child != null : true); - ModularRouter copyWith( + ModularRoute copyWith( {ModularChild? child, String? routerName, ChildModule? module, - List? children, - List? routerOutlet, + List? children, + List? routerOutlet, ChildModule? currentModule, Map? params, List? guards, @@ -233,7 +233,7 @@ class ModularRouter { Completer? popRoute, ModularArguments? args, CustomTransition? customTransition}) { - return ModularRouter( + return ModularRoute( routerName ?? this.routerName, child: child ?? this.child, args: args ?? this.args, @@ -257,7 +257,7 @@ class ModularRouter { bool operator ==(Object o) { if (identical(this, o)) return true; - return o is ModularRouter && + return o is ModularRoute && o.modulePath == modulePath && o.routerName == routerName && o.module == module; diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/modules/child_module.dart index f1efb444..8598ff1c 100644 --- a/flutter_modular/lib/src/core/modules/child_module.dart +++ b/flutter_modular/lib/src/core/modules/child_module.dart @@ -4,12 +4,12 @@ import '../errors/errors.dart'; import '../inject/bind.dart'; import '../inject/inject.dart'; import '../interfaces/disposable.dart'; -import '../models/modular_router.dart'; +import '../models/modular_route.dart'; @immutable abstract class ChildModule { late final List binds; - late final List routers; + late final List routers; @visibleForTesting void changeBinds(List b) { diff --git a/flutter_modular/lib/src/presenters/navigation/modular_page.dart b/flutter_modular/lib/src/presenters/navigation/modular_page.dart index 7b1ff016..87f7bc7e 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_page.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_page.dart @@ -2,12 +2,12 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; -import '../../core/models/modular_router.dart'; +import '../../core/models/modular_route.dart'; final Map _allCompleters = {}; class ModularPage extends Page { - final ModularRouter router; + final ModularRoute router; ModularPage({LocalKey? key, required this.router}) : super(key: key, name: router.path, arguments: router.args?.data); @@ -72,8 +72,8 @@ class ModularPage extends Page { } } -class ModularRoute extends Route { +class ModularRouteSettings extends Route { final ModularPage page; - ModularRoute(this.page) : super(settings: page); + ModularRouteSettings(this.page) : super(settings: page); } diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 524560c5..61d7c754 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; import '../../core/errors/errors.dart'; -import '../../core/models/modular_router.dart'; +import '../../core/models/modular_route.dart'; import '../../core/modules/child_module.dart'; import '../modular_base.dart'; class ModularRouteInformationParser - extends RouteInformationParser { + extends RouteInformationParser { @override - Future parseRouteInformation( + Future parseRouteInformation( RouteInformation routeInformation) async { final path = routeInformation.location ?? '/'; final route = await selectRoute(path); @@ -16,7 +16,7 @@ class ModularRouteInformationParser } @override - RouteInformation restoreRouteInformation(ModularRouter router) { + RouteInformation restoreRouteInformation(ModularRoute router) { return RouteInformation( location: router.routerOutlet.isEmpty ? router.path @@ -24,7 +24,7 @@ class ModularRouteInformationParser ); } - ModularRouter? _searchInModule( + ModularRoute? _searchInModule( ChildModule module, String routerName, String path) { path = "/$path".replaceAll('//', '/'); final routers = @@ -41,9 +41,9 @@ class ModularRouteInformationParser return null; } - ModularRouter? _normalizeRoute( - ModularRouter route, String routerName, String path) { - ModularRouter? router; + ModularRoute? _normalizeRoute( + ModularRoute route, String routerName, String path) { + ModularRoute? router; if (routerName == path || routerName == "$path/") { router = route.module!.routers[0]; if (router.module != null) { @@ -59,8 +59,8 @@ class ModularRouteInformationParser return router; } - ModularRouter? _searchRoute( - ModularRouter route, String routerName, String path) { + ModularRoute? _searchRoute( + ModularRoute route, String routerName, String path) { final tempRouteName = (routerName + route.routerName).replaceFirst('//', '/'); if (route.child == null) { @@ -144,8 +144,8 @@ class ModularRouteInformationParser return newUrl.join("/"); } - ModularRouter _parseUrlParams( - ModularRouter router, String routeNamed, String path) { + ModularRoute _parseUrlParams( + ModularRoute router, String routeNamed, String path) { if (routeNamed.contains('/:')) { final regExp = RegExp( "^${prepareToRegex(routeNamed)}\$", @@ -183,11 +183,11 @@ class ModularRouteInformationParser return router.copyWith(path: routeNamed); } - ModularRouter? _searchWildcard( + ModularRoute? _searchWildcard( String path, ChildModule module, ) { - ModularRouter? finded; + ModularRoute? finded; final segments = path.split('/')..removeLast(); final length = segments.length; @@ -214,7 +214,7 @@ class ModularRouteInformationParser return finded?.routerName == '**' ? finded : null; } - Future selectRoute(String path, [ChildModule? module]) async { + Future selectRoute(String path, [ChildModule? module]) async { if (path.isEmpty) { throw Exception("Router can not be empty"); } @@ -229,7 +229,7 @@ class ModularRouteInformationParser throw ModularError('Route \'$path\' not found'); } - Future canActivate(String path, ModularRouter router) async { + Future canActivate(String path, ModularRoute router) async { if (router.guards?.isNotEmpty == true) { for (var guard in router.guards!) { try { diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index aa6609dd..e1039eea 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_modular/src/core/models/modular_route.dart'; -import '../../core/models/modular_router.dart'; import '../../core/modules/child_module.dart'; import '../interfaces/modular_navigator_interface.dart'; import '../modular_base.dart'; @@ -9,11 +9,11 @@ import 'custom_navigator.dart'; import 'modular_page.dart'; import 'modular_route_information_parser.dart'; -class ModularRouterDelegate extends RouterDelegate +class ModularRouterDelegate extends RouterDelegate with // ignore: prefer_mixin ChangeNotifier, - PopNavigatorRouterDelegateMixin + PopNavigatorRouterDelegateMixin implements IModularNavigator { final GlobalKey navigatorKey = GlobalKey(); @@ -34,7 +34,7 @@ class ModularRouterDelegate extends RouterDelegate final routerOutlatPages = >{}; @override - ModularRouter? get currentConfiguration => + ModularRoute? get currentConfiguration => _pages.isEmpty ? null : _pages.last.router; @override @@ -49,7 +49,7 @@ class ModularRouterDelegate extends RouterDelegate } @override - Future setNewRoutePath(ModularRouter router, + Future setNewRoutePath(ModularRoute router, [bool execRebuild = true]) async { final page = ModularPage( key: ValueKey('url:${router.path}'), diff --git a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart index 9baf69ca..74356306 100644 --- a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; -import '../../core/models/modular_router.dart'; +import '../../core/models/modular_route.dart'; import '../modular_base.dart'; import 'custom_navigator.dart'; import 'modular_page.dart'; import 'modular_router_delegate.dart'; -class RouterOutletDelegate extends RouterDelegate +class RouterOutletDelegate extends RouterDelegate with // ignore: prefer_mixin ChangeNotifier, - PopNavigatorRouterDelegateMixin { + PopNavigatorRouterDelegateMixin { final GlobalKey navigatorKey; final ModularRouterDelegate modularRouterDelegate; @@ -69,7 +69,7 @@ class RouterOutletDelegate extends RouterDelegate } @override - Future setNewRoutePath(ModularRouter router) async { + Future setNewRoutePath(ModularRoute router) async { assert(false); } } diff --git a/flutter_modular/lib/src/presenters/widgets/widget_module.dart b/flutter_modular/lib/src/presenters/widgets/widget_module.dart index bd990aa7..7c36a25f 100644 --- a/flutter_modular/lib/src/presenters/widgets/widget_module.dart +++ b/flutter_modular/lib/src/presenters/widgets/widget_module.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; import '../../core/inject/bind.dart'; -import '../../core/models/modular_router.dart'; +import '../../core/models/modular_route.dart'; import '../../core/modules/child_module.dart'; import '../modular_base.dart'; @@ -51,7 +51,7 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { } @override - List routers = const []; + List routers = const []; @override Widget build(BuildContext context) { @@ -73,7 +73,7 @@ class _FakeModule extends ChildModule { List get binds => bindsInject ?? []; @override - List get routers => []; + List get routers => []; } class ModularProvider extends StatefulWidget { diff --git a/flutter_modular/test/src/core/models/modular_router_test.dart b/flutter_modular/test/src/core/models/modular_router_test.dart index c2537e21..501702bd 100644 --- a/flutter_modular/test/src/core/models/modular_router_test.dart +++ b/flutter_modular/test/src/core/models/modular_router_test.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/core/models/modular_router.dart'; +import 'package:flutter_modular/src/core/models/modular_route.dart'; import 'package:flutter_test/flutter_test.dart'; import '../modules/child_module_test.dart'; @@ -7,23 +7,23 @@ import '../modules/child_module_test.dart'; main() { test('should initializa in incorrect form', () { expect( - () => ModularRouter('/', + () => ModularRoute('/', child: (context, args) => Container(), module: ModuleMock()), throwsAssertionError); expect( - () => ModularRouter('/', + () => ModularRoute('/', transition: TransitionType.custom, module: ModuleMock()), throwsAssertionError); expect( - () => ModularRouter('/', - children: [ModularRouter('/')], module: ModuleMock()), + () => ModularRoute('/', + children: [ModularRoute('/')], module: ModuleMock()), throwsAssertionError); }); test('should make copy with implementation', () { - final model = ModularRouter('/', module: ModuleMock()); + final model = ModularRoute('/', module: ModuleMock()); final copy = model.copyWith(); expect(copy.module, isA()); final copy2 = model.copyWith(path: '/home'); @@ -34,7 +34,7 @@ main() { }); test('should normal instance custom transition', () { - final model = ModularRouter('/', + final model = ModularRoute('/', transition: TransitionType.custom, module: ModuleMock(), customTransition: CustomTransition(transitionBuilder: (c, a1, a2, w) { return FadeTransition( diff --git a/flutter_modular/test/src/core/modules/child_module_test.dart b/flutter_modular/test/src/core/modules/child_module_test.dart index a8e22b53..a4326b3e 100644 --- a/flutter_modular/test/src/core/modules/child_module_test.dart +++ b/flutter_modular/test/src/core/modules/child_module_test.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; import 'package:flutter_modular/src/core/inject/bind.dart'; -import 'package:flutter_modular/src/core/models/modular_router.dart'; +import 'package:flutter_modular/src/core/models/modular_route.dart'; import 'package:flutter_modular/src/core/modules/child_module.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -18,7 +18,7 @@ class ModuleMock extends ChildModule { ]; @override - List routers = []; + List routers = []; } main() { diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index ebb5a9fc..cdbfb6ef 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -148,17 +148,17 @@ class ModuleMock extends ChildModule { ]; @override - final List routers = [ - ModularRouter( + final List routers = [ + ModularRoute( '/', child: (context, args) => Container(), ), - ModularRouter( + ModularRoute( '/home', child: (context, args) => Scaffold(), children: [ - ModularRouter('/tab1', child: (context, args) => TextField()), - ModularRouter( + ModularRoute('/tab1', child: (context, args) => TextField()), + ModularRoute( '/tab2/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], @@ -166,22 +166,22 @@ class ModuleMock extends ChildModule { ), ], ), - ModularRouter('/mock', module: ModuleMock2()), - ModularRouter('/guarded', + ModularRoute('/mock', module: ModuleMock2()), + ModularRoute('/guarded', guards: [MyGuardModule()], module: ModuleGuarded()), - ModularRouter('/list', child: (context, args) => ListView()), - ModularRouter( + ModularRoute('/list', child: (context, args) => ListView()), + ModularRoute( '/401', guards: [MyGuard()], child: (context, args) => SingleChildScrollView(), ), - ModularRouter( + ModularRoute( '/list/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], ), ), - ModularRouter('**', child: (context, args) => FlutterLogo()) + ModularRoute('**', child: (context, args) => FlutterLogo()) ]; } @@ -195,26 +195,26 @@ class ModuleMock2 extends ChildModule { ]; @override - final List routers = [ - ModularRouter('/', child: (context, args) => SizedBox(), children: [ - ModularRouter('/home', child: (context, args) => Container()), + final List routers = [ + ModularRoute('/', child: (context, args) => SizedBox(), children: [ + ModularRoute('/home', child: (context, args) => Container()), ]), - ModularRouter( + ModularRoute( '/list', child: (context, args) => ListView(), ), - ModularRouter( + ModularRoute( '/listguarded', guards: [MyGuard()], child: (context, args) => ListView(), ), - ModularRouter( + ModularRoute( '/list/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], ), ), - ModularRouter('**', child: (context, args) => FlutterLogo()) + ModularRoute('**', child: (context, args) => FlutterLogo()) ]; } @@ -228,27 +228,27 @@ class ModuleGuarded extends ChildModule { ]; @override - final List routers = [ - ModularRouter('/', child: (context, args) => SizedBox(), children: [ - ModularRouter('/home', child: (context, args) => Container()), - ModularRouter('/guarded', child: (context, args) => Container()), + final List routers = [ + ModularRoute('/', child: (context, args) => SizedBox(), children: [ + ModularRoute('/home', child: (context, args) => Container()), + ModularRoute('/guarded', child: (context, args) => Container()), ]), - ModularRouter( + ModularRoute( '/list', child: (context, args) => ListView(), ), - ModularRouter( + ModularRoute( '/listguarded', guards: [MyGuard()], child: (context, args) => ListView(), ), - ModularRouter( + ModularRoute( '/list/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], ), ), - ModularRouter('**', child: (context, args) => FlutterLogo()) + ModularRoute('**', child: (context, args) => FlutterLogo()) ]; } @@ -270,7 +270,7 @@ class CustomWidget extends StatelessWidget { class MyGuard implements RouteGuard { @override - Future canActivate(String path, ModularRouter router) async { + Future canActivate(String path, ModularRoute router) async { if (path == '/401') { return false; } else if (path == '/mock/listguarded') { @@ -283,7 +283,7 @@ class MyGuard implements RouteGuard { class MyGuardModule implements RouteGuard { @override - Future canActivate(String path, ModularRouter router) async { + Future canActivate(String path, ModularRoute router) async { if (path == '/guarded/list') { return false; } else { From 0a2a2e8ad9579cc856607853b1b93a369465eb15 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 9 Dec 2020 19:27:41 -0300 Subject: [PATCH 52/71] documentation --- flutter_modular/README.md | 342 +++++++----------- .../lib/src/core/modules/main_module.dart | 2 +- flutter_modular/pubspec.yaml | 2 +- 3 files changed, 124 insertions(+), 222 deletions(-) diff --git a/flutter_modular/README.md b/flutter_modular/README.md index 8b6199ce..f8f17f89 100644 --- a/flutter_modular/README.md +++ b/flutter_modular/README.md @@ -52,6 +52,8 @@ As an application project grows and becomes complex, it's hard to keep your code Modular's dependency injection system has out-of-the-box support for any state management system, managing your application memory usage. +Modular also supports Dynamic and Relative Routing like in the Web. + ## Modular Structure Modular structure consists in decoupled and independent modules that will represent the features of the application. @@ -64,12 +66,9 @@ These are the main aspects that Modular focus on: - Automatic Memory Management. - Dependency Injection. -- Dynamic Routing. +- Dynamic and Relative Routing. - Code Modularization. -## Examples - -- [Github Search](https://github.com/Flutterando/github_search) # Getting started with Modular @@ -82,20 +81,11 @@ dependencies: flutter_modular: any ``` -You can also provide the git repository as source instead, to try out the newest features and fixes: - -```yaml -dependencies: - flutter_modular: - git: - url: https://github.com/Flutterando/modular -``` - ## Using in a new project To use Modular in a new project, you will have to make some initial setup: -1. Create your main widget with a `MaterialApp` and set its `initialRoute`. On `onGenerateroute`, you will have to provide Modular's routing system (`Modular.generateRoute`), so it can manage your routes. +1. Create your main widget with a `MaterialApp` and call the ´´´MaterialApp().modular()´´´ method. ```dart // app_widget.dart @@ -106,17 +96,13 @@ class AppWidget extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - // set your initial route initialRoute: "/", - navigatorKey: Modular.navigatorKey, - // add Modular to manage the routing system - onGenerateRoute: Modular.generateRoute, - ); + ).modular(); } } ``` -2. Create your project's main module file extending `MainModule`: +2. Create your project main module file extending `MainModule`: ```dart // app_module.dart @@ -124,20 +110,20 @@ class AppModule extends MainModule { // Provide a list of dependencies to inject into your project @override - List get binds => []; + final List binds = []; // Provide all the routes for your module @override - List get routers => []; + final List routers = []; // Provide the root widget associated with your module // In this case, it's the widget you created in the first step @override - Widget get bootstrap => AppWidget(); + final Widget bootstrap => AppWidget(); } ``` -3. In your `main.dart`, wrap your main module in `ModularApp` to initialize it with Modular: +3. In `main.dart` file, wrap the main module in `ModularApp` to initialize it with Modular: ```dart // main.dart @@ -151,9 +137,10 @@ void main() => runApp(ModularApp(module: AppModule())); 4. Done! Your app is set and ready to work with Modular! + ## Adding routes -Your module's routes are provided by overriding the `routers` getter: +The module routes are provided by overriding the `routers`: ```dart // app_module.dart @@ -161,22 +148,28 @@ class AppModule extends MainModule { // Provide a list of dependencies to inject into your project @override - List get binds => []; + final List binds = []; // Provide all the routes for your module @override - List get routers => [ + final List routers = [ ModularRoute('/', child: (_, __) => HomePage()), ModularRoute('/login', child: (_, __) => LoginPage()), ]; // Provide the root widget associated with your module @override - Widget get bootstrap => AppWidget(); + final Widget bootstrap = AppWidget(); } ``` -To push your route to your app, you can use `Navigator.pushNamed`: +To navigate between pages, use `Modular.to.navigate`. + +```dart +Modular.to.navigate('/login'); +``` + +You can also stack pages still using old Navigator API. ```dart Navigator.pushNamed(context, '/login'); @@ -188,24 +181,24 @@ Alternatively, you can use `Modular.to.pushNamed`, in which you don't have to pr Modular.to.pushNamed('/login'); ``` -### Navigation on the current module +### Relative Navigation -Use `Modular.to` for literal paths or `Modular.link` for routes in current module: +You can use Relative Navigation to navigate like web ```dart // Modules Home → Product -Modular.to.pushNamed('/home/product/list'); -Modular.to.pushNamed('/home/product/detail/:id'); +Modular.to.navigate('/home/product/list'); +Modular.to.navigate('/home/product/detail/:id'); -// Inside Product module, use Modular.link and navigate between Product module routes -Modular.link.pushNamed('/list'); -Modular.link.pushNamed('/detail/:id'); +// Relative Navigation inside /home/product/list +Modular.to.navigate('detail/3'); // it's the same as /home/product/detail/3 +Modular.to.navigate('../config'); // it's the same as /home/config ``` ## Dynamic routes -You can use the dynamic routing system to provide parameters to your `Router`: +You can use dynamic routing system to provide parameters to your `Route`: ```dart // Use :parameter_name syntax to provide a parameter in your route. @@ -213,7 +206,7 @@ You can use the dynamic routing system to provide parameters to your `Router`: // using square brackets notation (['parameter_name']). @override -List get routers => [ +finalList routers = [ ModularRoute( '/product/:id', child: (_, args) => Product(id: args.params['id']), @@ -221,7 +214,7 @@ List get routers => [ ]; ``` -The parameter will, then, be pattern-matched when calling the given route. For example: +The parameter will be pattern-matched when calling the given route. For example: ```dart // In this case, `args.params['id']` will have the value `1`. @@ -238,7 +231,7 @@ And it will be available in the `args.data` property instead of `args.params`: ```dart @override -List get routers => [ +final List routers = [ ModularRoute( '/product', child: (_, args) => Product(model: args.data), @@ -255,7 +248,7 @@ For example, the following class will only allow a redirection from `/admin` rou ```dart class MyGuard implements RouteGuard { @override - bool canActivate(String url) { + bool canActivate(String url, ModularRoute route) { if (url != '/admin'){ // Return `true` to allow access return true; @@ -271,9 +264,9 @@ To use your `RouteGuard` in a route, pass it to the `guards` parameter: ```dart @override -List get routers => [ - ModularRoute('/', module: HomeModule()), - ModularRoute( +List routers = [ + final ModularRoute('/', module: HomeModule()), + final ModularRoute( '/admin', module: AdminModule(), guards: [MyGuard()], @@ -286,7 +279,7 @@ If placed on a module route, `RouterGuard` will be global to that route. ## Route transition animation -You can choose which type of animation you want to be used on your pages transition by setting the `Router`'s `transition` parameter, providing a `TransitionType`. +You can choose which type of animation do you want to be used on your pages transition by setting the `Route` `transition` parameter, providing a `TransitionType`. ```dart ModularRoute('/product', @@ -346,44 +339,27 @@ CustomTransition get myCustomTransition => CustomTransition( ); ``` -## Grouping routes - -You can group routes that contains one or more common properties. Properties like `guards`, `transition` and `customTransition` can be provided both for single routes and groups of routes: - -```dart -List get routers => [ - ModularRoute('/', module: HomeModule()), - Router.group( - guards: [MyGuard()], - routes: [ - ModularRoute("/admin", module: AdminModule()), - ModularRoute("/profile", module: ProfileModule()), - ], - ), -); -``` - -## Router generic types +## Route generic types You can return values from navigation, just like `.pop`. -To achieve this, pass the type you expect to return as type parameter to `Router`: +To achieve this, pass the type you expect to return as type parameter to `Route`: ```dart @override -List get routers => [ +final List routers => [ // This router expects to receive a `String` when popped. - Router('/event', child: (_, __) => EventPage()), + ModularRoute('/event', child: (_, __) => EventPage()), ] ``` -Now, use `.pop` as you would with `Navigator.pop`: +Now, use `.pop` as you use with `Navigator.pop`: ```dart // Push route String name = await Modular.to.pushNamed(); // And pass the value when popping -Modular.to.pop('Jacob Moura'); +Modular.to.pop('banana'); ``` ## Flutter Web URL routes (Deeplink-like) @@ -397,9 +373,9 @@ https://flutter-website.com/#/product/1 ## Dependency Injection -You can inject any class into your module by overriding the `binds` getter of your module. Typical examples to inject are BLoCs, ChangeNotifier classes or stores. +You can inject any class into your module by overriding the `binds` getter of your module. Typical examples to inject are BLoCs, ChangeNotifier classes or stores(MobX). -A `Bind` object is responsible for configuring the object injection. +A `Bind` object is responsible for configuring the object injection. We have 4 Bind factory types. ```dart class AppModule extends MainModule { @@ -407,22 +383,21 @@ class AppModule extends MainModule { // Provide a list of dependencies to inject into your project @override List get binds => [ - Bind((_) => AppBloc()), // Injecting a BLoC - Bind((_) => Counter()), // Injecting a ChangeNotifier class - ]; - - // Provide all the routes for your module - @override - List get routers => [ - ModularRoute('/', child: (_, args) => HomePage()), - ModularRoute('/login', child: (_, args) => LoginPage()), + Bind((i) => AppBloc()), + Bind.factory((i) => AppBloc()), + Bind.instance(myObject), + Bind.singleton((i) => AppBloc()), + Bind.lazySingleton((i) => AppBloc()), ]; - - // Provide the root widget associated with your module - @override - Widget get bootstrap => AppWidget(); +... } ``` +**factory**: Instantiate the class whenever it gets called.
+**instance**: Use a class that has already been instantiated.
+**singleton**: Create a Global instance of a class.
+**lazySingleton**: Create a Global instance of a class only when it gets called for the first time.
+

+ ### Retrieving your injected dependencies in the view @@ -459,20 +434,7 @@ class HomePage extends StatelessWidget { } ``` -By default, objects in Bind are singletons and lazy. -When Bind is lazy, the object will only be instantiated when it is called for the first time. You can use 'lazy: false' if you want your object to be instantiated immediately (eager-loaded). - -```dart -Bind((i) => OtherWidgetNotLazy(), lazy: false), -``` - -If you want the injected object to be instantiated every time it is called (instead of being a singleton instance), you may simple pass `false` to the `singleton` parameter: - -```dart -Bind((i) => OtherWidgetNotLazy(), singleton: false), -``` - -## Using Modular widgets to retrieve your classes +## Using Modular widgets to retrieve your class ### ModularState @@ -499,52 +461,6 @@ class _MyWidgetState extends ModularState { } ``` -## Consuming a ChangeNotifier class - -Example of a `ChangeNotifier` class: - -```dart -import 'package:flutter/material.dart'; - -class Counter extends ChangeNotifier { - int counter = 0; - - increment() { - counter++; - notifyListeners(); - } -} -``` - -you can use the `Consumer` to manage the state of a widget block. - -```dart -class HomePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - - return Scaffold( - appBar: AppBar(title: Text("Home")), - body: Center( - // By passing your ChangeNotifier class as type parameter, the `builder` will be called every time `notifyListeners` is called - child: Consumer( - builder: (context, value) { - return Text('Counter ${value.counter}'); - } - ), - ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - onPressed: () { - // You can retrive the class directly with `get` and execute the increment method - get().increment(); - }, - ), - ); - } -} -``` - ## Creating child modules You can create as many modules in your project as you wish, but they will be dependent of the main module. To do so, instead of inheriting from `MainModule`, you should inherit from `ChildModule`: @@ -552,33 +468,32 @@ You can create as many modules in your project as you wish, but they will be dep ```dart class HomeModule extends ChildModule { @override - List get binds => [ - Bind((i) => HomeBloc()), + final List binds = [ + Bind.singleton((i) => HomeBloc()), ]; @override - List get routers => [ + final List routers = [ ModularRoute('/', child: (_, args) => HomeWidget()), ModularRoute('/list', child: (_, args) => ListWidget()), ]; - static Inject get to => Inject.of(); } ``` -You may then pass the submodule to a `Router` in your main module through the `module` parameter: +You may then pass the submodule to a `Route` in your main module through the `module` parameter: ```dart class AppModule extends MainModule { @override - List get routers => [ + final List routers = [ ModularRoute('/home', module: HomeModule()), ]; } ``` -We recommend that you split your code in various modules, such as `LoginModule`, and place all the routes related to this module within it. By doing so, it will much easier to maintain and share your code with other projects. +We recommend that you split your code in various modules, such as `AuthModule`, and place all the routes related to this module within it. By doing so, it will much easier to maintain and share your code with other projects. ### WidgetModule @@ -587,13 +502,13 @@ We recommend that you split your code in various modules, such as `LoginModule`, ```dart class TabModule extends WidgetModule { - @override - List get binds => [ + @override + final List binds => [ Bind((i) => TabBloc(repository: i())), Bind((i) => TabRepository()), ]; - Widget get view => TabPage(); + final Widget view = TabPage(); } @@ -601,55 +516,67 @@ class TabModule extends WidgetModule { ## RouterOutlet -A `RouterOutlet` may be used if you need a routing system that is totally detached from the main routing system. This is useful, for example, when you need an element to have its own set of routes, even though it is inside a page on the main route. - -A practical example of this is its use in a `TabBar` or `Drawer`: +Cada ModularRoute pode ter uma lista de ModularRoutes, para que possa ser exibido dentro do ModularRoute pai. +O Widget que reflete essas rotas internas é chamado de `RouterOutlet`. +Você pode ter apenas um `RouterOutlet` por página e ele só é capaz de navegar pelos filhos dessa página. ```dart -PageView( - controller: controller - children: [ - RouterOutlet( - module: Tab1Module() - ), - RouterOutlet( - module: Tab2Module() - ), - RouterOutlet( - module: Tab3Module() - ), - ] -), -``` -> **NOTE:** Navigation within these modules are only supported through `Navigator.of(context)` or `Modular.navigator` using literal routes paths. + class StartModule extends ChildModule { + @override + final List binds = []; -## RouterOutletList + @override + final List routers = [ + ModularRoute( + '/start', + child: (context, args) => StartPage(), + children: [ + ModularRoute('/home', child: (_, __) => HomePage()), + ModularRoute('/product', child: (_, __) => ProductPage()), + ModularRoute('/config', child: (_, __) => ConfigPage()), + ], + ), + ]; + } -Using multiples RouterOutlets. +``` ```dart - var controller = RouterOutletListController(); - controller.listen((value) { - setState(() { - currentIndex = value; - }); - }); -.... - RouterOutletList( - modules: [ - Tab1Module(), - Tab2Module(), - ], controller: controller, - ), + @override + Widget build(BuildContext context) { + return Scaffold( + body: RouterOutlet(), + bottomNavigationBar: BottomNavigationBar( + onTap: (id) { + if (id == 0) { + Modular.to.navigate('/start/home'); + } else if (id == 1) { + Modular.to.navigate('/start/product'); + } else if (id == 2) { + Modular.to.navigate('/start/config'); + } + }, + currentIndex: currentIndex, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + label: 'Home', + ), + BottomNavigationBarItem( + icon: Icon(Icons.control_camera), + label: 'product', + ), + BottomNavigationBarItem( + icon: Icon(Icons.settings), + label: 'Config', + ), + ], + ), + ); + } ``` - - -## Lazy loading - -Another benefit you get when working with modules is that they are (by default) lazily-loaded. This means that your dependency injection will only be available when you navigate to a module, and when you exit that module, Modular will manage the resources disposal by removing all injections and executing `dispose()` (if available) on each injected dependency. - ## Unit test You can use the dependency injection system to replace a `Bind` with a mocked `Bind`, like, for example, a mocked repository. You can also do it using "Inversion of Control" (IoC). @@ -658,12 +585,12 @@ For example, you can make a repository interface (`ILocalStorage`) that satisfie ```dart @override -List get binds => [ +final List binds => [ Bind((i) => LocalStorageSharePreferences()), ]; ``` -Then, on your test file, you import `flutter_modular_test` and provide your mocked repository in the `initModule` as a replacement of your concrete repository: +On your test file, you import `flutter_modular_test` and provide your mocked repository in the `initModule` as a replacement of your concrete repository: ```dart import 'package:flutter_modular/flutter_modular_test.dart'; @@ -906,31 +833,6 @@ We though it would be interesting to provide a native way to mock the navigation Modular.navigatorDelegate = MyNavigatorMock(); ``` -## DebugMode - -By default, Modular prints a lot of debug info in the console. You may disable this by disabling `debugMode`: - -```dart -Modular.debugMode = false; -``` - -## Roadmap - -This is our current roadmap. Please, feel free to request additions/changes. - -| Feature | Progress | -| :-------------------------------- | :------: | -| DI by Module | ✅ | -| Routes by Module | ✅ | -| Widget Consume for ChangeNotifier | ✅ | -| Auto-dispose | ✅ | -| Integration with flutter_bloc | ✅ | -| Integration with mobx | ✅ | -| Multiple routes | ✅ | -| Pass arguments by route | ✅ | -| Pass url parameters per route | ✅ | -| Route Transition Animation | ✅ | - ## Features and bugs Please send feature requests and bugs at the [issue tracker](https://github.com/Flutterando/modular/issues). diff --git a/flutter_modular/lib/src/core/modules/main_module.dart b/flutter_modular/lib/src/core/modules/main_module.dart index f3f870d0..a4e9cff7 100644 --- a/flutter_modular/lib/src/core/modules/main_module.dart +++ b/flutter_modular/lib/src/core/modules/main_module.dart @@ -3,5 +3,5 @@ import 'package:flutter/widgets.dart'; import 'child_module.dart'; abstract class MainModule extends ChildModule { - Widget get bootstrap; + late final Widget bootstrap; } diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index fbd0f25f..e9de2e79 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.8 +version: 3.0.0-nullsafety.9 homepage: https://github.com/Flutterando/modular environment: From 8fa3782be593d0bcd0dfd8cfaf81515f66b3c14d Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 9 Dec 2020 19:33:33 -0300 Subject: [PATCH 53/71] . --- flutter_modular/README.md | 17 ++++++----------- flutter_modular/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/flutter_modular/README.md b/flutter_modular/README.md index f8f17f89..7d462523 100644 --- a/flutter_modular/README.md +++ b/flutter_modular/README.md @@ -15,8 +15,6 @@ - **[Modular Structure](#modular-structure)** - **[Modular Pillars](#modular-pillars)** - - [Example](#example) - - **[Getting started with Modular](#getting-started-with-modular)** - [Installation](#installation) @@ -25,7 +23,6 @@ - [Dynamic Routes](#dynamic-routes) - [Route Guard](#route-guard) - [Route Transition Animation](#route-transition-animation) - - [Grouping Routes](#grouping-routes) - [Flutter Web url Routes](#flutter-web-url-routes) - [Dependency Injection](#dependency-injection) - [Retrieving in view using injection](#retrieving-in-view-using-injection) @@ -37,8 +34,6 @@ - [Creating Child Modules](#creating-child-modules) - [WidgetModule](#widgetmodule) - [RouterOutlet](#routeroutlet) - - [RouterOutletList](#routeroutletlist) - - [Lazy Loading](#lazy-loading) - [Unit Test](#unit-test) - [Modular test helper](#modular-test-helper) - [DebugMode](#debugmode) @@ -516,9 +511,9 @@ class TabModule extends WidgetModule { ## RouterOutlet -Cada ModularRoute pode ter uma lista de ModularRoutes, para que possa ser exibido dentro do ModularRoute pai. -O Widget que reflete essas rotas internas é chamado de `RouterOutlet`. -Você pode ter apenas um `RouterOutlet` por página e ele só é capaz de navegar pelos filhos dessa página. +Each ModularRoute can have a list of ModularRoutes, so that it can be displayed within the parent ModularRoute. +The widget that reflects these internal routes is called `RouterOutlet`. +You can only have one `RouterOutlet` per page and it is only able to browse the children of that page. ```dart @@ -622,16 +617,16 @@ class InitAppModuleHelper extends IModularTest { IModularTest({this.modularTestType: ModularTestType.resetModule}); @override - List get binds => [ + List binds = [ Bind((i) => LocalStorageSharePreference()), ]; @override - ChildModule get module => AppModule(); + final ChildModule module = AppModule(); @override - IModularTest get modulardependency => null; + final IModularTest modulardependency = null; } diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index e9de2e79..29572fa5 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.9 +version: 3.0.0-nullsafety.10 homepage: https://github.com/Flutterando/modular environment: From 5dc49ae88c50194aa6442312de68e45d453a62ca Mon Sep 17 00:00:00 2001 From: Thiago Fernandes Date: Wed, 9 Dec 2020 19:55:48 -0300 Subject: [PATCH 54/71] fix README.md index --- flutter_modular/README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/flutter_modular/README.md b/flutter_modular/README.md index 7d462523..97ee5f5a 100644 --- a/flutter_modular/README.md +++ b/flutter_modular/README.md @@ -23,22 +23,23 @@ - [Dynamic Routes](#dynamic-routes) - [Route Guard](#route-guard) - [Route Transition Animation](#route-transition-animation) - - [Flutter Web url Routes](#flutter-web-url-routes) + - [Flutter Web url Routes](#flutter-web-url-routes-deeplink-like) - [Dependency Injection](#dependency-injection) - - [Retrieving in view using injection](#retrieving-in-view-using-injection) + - [Retrieving your injected dependencies in the view](#retrieving-your-injected-dependencies-in-the-view) -- **[Using Modular widgets to retrieve your classes](#using-modular-widgets-to-retrieve-your-classes)** +- **[Using Modular widgets to retrieve your class](#using-modular-widgets-to-retrieve-your-class)** - [ModularState](#modularstate) - - [Consuming a ChangeNotifier Class](#consuming-a-changenotifier-class) - [Creating Child Modules](#creating-child-modules) - [WidgetModule](#widgetmodule) - [RouterOutlet](#routeroutlet) - [Unit Test](#unit-test) - [Modular test helper](#modular-test-helper) - - [DebugMode](#debugmode) + - [Load Modular helper on tests](#load-modular-helper-on-tests) + - [Create helper for a child module](#create-helper-for-a-child-module) + - [Mocking with mockito](#mocking-with-mockito) + - [Mock the navigation system](#mock-the-navigation-system) -- **[Roadmap](#roadmap)** - **[Features and bugs](#features-and-bugs)** ## What is Flutter Modular? @@ -394,7 +395,7 @@ class AppModule extends MainModule {

-### Retrieving your injected dependencies in the view +## Retrieving your injected dependencies in the view Let's assume the following BLoC has been defined and injected in our module (as in the previous example): From 5a3bd6ec73fc64c58c90b552536c5287a8a7a7b4 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Thu, 10 Dec 2020 15:05:29 -0300 Subject: [PATCH 55/71] fix doc --- flutter_modular/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/README.md b/flutter_modular/README.md index 7d462523..62a6abd8 100644 --- a/flutter_modular/README.md +++ b/flutter_modular/README.md @@ -243,7 +243,7 @@ For example, the following class will only allow a redirection from `/admin` rou ```dart class MyGuard implements RouteGuard { @override - bool canActivate(String url, ModularRoute route) { + Future canActivate(String url, ModularRoute route) { if (url != '/admin'){ // Return `true` to allow access return true; From 1331d3662f4800ea4029fcdc52a6d9f81867e891 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Thu, 10 Dec 2020 23:18:26 -0300 Subject: [PATCH 56/71] remove files --- .../modular_route_information_parser.dart | 179 --------- .../delegates/modular_router_delegate.dart | 181 --------- .../.src/exceptions/modular_error.dart | 10 - flutter_modular/.src/inject/bind.dart | 53 --- flutter_modular/.src/inject/inject.dart | 36 -- .../.src/interfaces/child_module.dart | 114 ------ .../.src/interfaces/disposable.dart | 7 - .../.src/interfaces/main_module.dart | 7 - .../.src/interfaces/modular_interface.dart | 20 - .../modular_navigator_interface.dart | 104 ------ .../.src/interfaces/route_guard.dart | 6 - flutter_modular/.src/modular_base.dart | 63 ---- flutter_modular/.src/modular_impl.dart | 133 ------- .../.src/routers/modular_link.dart | 80 ---- .../.src/routers/modular_page.dart | 52 --- .../.src/routers/modular_router.dart | 346 ------------------ .../.src/test/modular_test_interface.dart | 95 ----- flutter_modular/.src/test/utils_test.dart | 44 --- .../.src/utils/modular_arguments.dart | 17 - flutter_modular/.src/widgets/modular_app.dart | 37 -- .../.src/widgets/modular_state.dart | 14 - .../.src/widgets/router_outlet.dart | 71 ---- .../.src/widgets/widget_module.dart | 107 ------ .../lib/src/presenters/modular_base.dart | 11 + .../navigation/modular_router_delegate.dart | 2 +- 25 files changed, 12 insertions(+), 1777 deletions(-) delete mode 100644 flutter_modular/.src/delegates/modular_route_information_parser.dart delete mode 100644 flutter_modular/.src/delegates/modular_router_delegate.dart delete mode 100644 flutter_modular/.src/exceptions/modular_error.dart delete mode 100644 flutter_modular/.src/inject/bind.dart delete mode 100644 flutter_modular/.src/inject/inject.dart delete mode 100644 flutter_modular/.src/interfaces/child_module.dart delete mode 100644 flutter_modular/.src/interfaces/disposable.dart delete mode 100644 flutter_modular/.src/interfaces/main_module.dart delete mode 100644 flutter_modular/.src/interfaces/modular_interface.dart delete mode 100644 flutter_modular/.src/interfaces/modular_navigator_interface.dart delete mode 100644 flutter_modular/.src/interfaces/route_guard.dart delete mode 100644 flutter_modular/.src/modular_base.dart delete mode 100644 flutter_modular/.src/modular_impl.dart delete mode 100644 flutter_modular/.src/routers/modular_link.dart delete mode 100644 flutter_modular/.src/routers/modular_page.dart delete mode 100644 flutter_modular/.src/routers/modular_router.dart delete mode 100644 flutter_modular/.src/test/modular_test_interface.dart delete mode 100644 flutter_modular/.src/test/utils_test.dart delete mode 100644 flutter_modular/.src/utils/modular_arguments.dart delete mode 100644 flutter_modular/.src/widgets/modular_app.dart delete mode 100644 flutter_modular/.src/widgets/modular_state.dart delete mode 100644 flutter_modular/.src/widgets/router_outlet.dart delete mode 100644 flutter_modular/.src/widgets/widget_module.dart diff --git a/flutter_modular/.src/delegates/modular_route_information_parser.dart b/flutter_modular/.src/delegates/modular_route_information_parser.dart deleted file mode 100644 index 2bbb812b..00000000 --- a/flutter_modular/.src/delegates/modular_route_information_parser.dart +++ /dev/null @@ -1,179 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../flutter_modular.dart'; - -class ModularRouteInformationParser - extends RouteInformationParser { - @override - Future parseRouteInformation( - RouteInformation routeInformation) async { - final path = routeInformation.location ?? '/'; - final route = await selectRoute(path); - return route; - } - - @override - RouteInformation restoreRouteInformation(ModularRoute router) { - return RouteInformation(location: router.path); - } - - ModularRoute? _searchInModule( - ChildModule module, String routerName, String path) { - path = "/$path".replaceAll('//', '/'); - final routers = - module.routers.map((e) => e.copyWith(currentModule: module)).toList(); - routers.sort((preview, actual) { - return preview.routerName.contains('/:') ? 1 : 0; - }); - for (var route in routers) { - var r = _searchRoute(route, routerName, path); - if (r != null) { - return r; - } - } - return null; - } - - ModularRoute? _normalizeRoute( - ModularRoute route, String routerName, String path) { - ModularRoute? router; - if (routerName == path || routerName == "$path/") { - router = route.module!.routers[0]; - if (router.module != null) { - var _routerName = - (routerName + route.routerName).replaceFirst('//', '/'); - router = _searchInModule(route.module!, _routerName, path); - } - } else { - router = _searchInModule(route.module!, routerName, path); - } - return router; - } - - ModularRoute? _searchRoute( - ModularRoute route, String routerName, String path) { - final tempRouteName = - (routerName + route.routerName).replaceFirst('//', '/'); - if (route.child == null) { - var _routerName = - ('$routerName${route.routerName}/').replaceFirst('//', '/'); - var router = _normalizeRoute(route, _routerName, path); - - if (router != null) { - router = router.copyWith( - modulePath: router.modulePath == null ? '/' : tempRouteName, - path: path, - ); - - if (router.transition == TransitionType.defaultTransition) { - router = router.copyWith( - transition: route.transition, - customTransition: route.customTransition, - ); - } - if (route.module != null) { - Modular.bindModule(route.module!, path); - } - return router; - } - } else { - if (tempRouteName.split('/').length != path.split('/').length) { - return null; - } - var parseRoute = _parseUrlParams(route, tempRouteName, path); - - if (path != parseRoute.path) { - return null; - } - - if (parseRoute.currentModule != null) { - Modular.bindModule(parseRoute.currentModule!, path); - return route.copyWith(path: path); - } - } - - return null; - } - - String prepareToRegex(String url) { - final newUrl = []; - for (var part in url.split('/')) { - var url = part.contains(":") ? "(.*?)" : part; - newUrl.add(url); - } - - return newUrl.join("/"); - } - - ModularRoute _parseUrlParams( - ModularRoute router, String routeNamed, String path) { - if (routeNamed.contains('/:')) { - final regExp = RegExp( - "^${prepareToRegex(routeNamed)}\$", - caseSensitive: true, - ); - var r = regExp.firstMatch(path); - if (r != null) { - var params = {}; - var paramPos = 0; - final routeParts = routeNamed.split('/'); - final pathParts = path.split('/'); - var newPath = router.path!; - - // print('Match! Processing $path as $routeNamed'); - - for (var routePart in routeParts) { - if (routePart.contains(":")) { - var paramName = routePart.replaceFirst(':', ''); - if (pathParts[paramPos].isNotEmpty) { - newPath = - newPath.replaceFirst(':$paramName', pathParts[paramPos]); - params[paramName] = pathParts[paramPos]; - routeNamed = - routeNamed.replaceFirst(routePart, params[paramName]!); - } - } - paramPos++; - } - - var _params = routeNamed != path ? null : params; - return router.copyWith( - args: router.args!.copyWith(params: _params), path: newPath); - } - - return router.copyWith(args: router.args!.copyWith(params: null)); - } - - return router; - } - - Future selectRoute(String path, [ChildModule? module]) async { - if (path.isEmpty) { - throw Exception("Router can not be empty"); - } - var route = _searchInModule(module ?? Modular.initialModule, "", path); - return canActivate(path, route); - } - - Future canActivate(String path, ModularRoute? router) async { - if (router == null) { - throw ModularError('Route not found'); - } - - if (router.guards?.isNotEmpty == true) { - for (var guard in router.guards!) { - try { - final result = await guard.canActivate(path, router); - if (!result) { - throw ModularError('$path is NOT ACTIVATE'); - } - // ignore: avoid_catches_without_on_clauses - } catch (e) { - throw ModularError( - 'RouteGuard error. Check ($path) in ${router.currentModule.runtimeType}'); - } - } - } - return router; - } -} diff --git a/flutter_modular/.src/delegates/modular_router_delegate.dart b/flutter_modular/.src/delegates/modular_router_delegate.dart deleted file mode 100644 index 85412e46..00000000 --- a/flutter_modular/.src/delegates/modular_router_delegate.dart +++ /dev/null @@ -1,181 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../flutter_modular.dart'; -import '../routers/modular_page.dart'; - -import 'modular_route_information_parser.dart'; - -class ModularRouteDelegate extends RouterDelegate - with - // ignore: prefer_mixin - ChangeNotifier, - PopNavigatorRouterDelegateMixin - implements - IModularNavigator { - final GlobalKey navigatorKey; - final ModularRouteInformationParser parser; - final Map injectMap; - - ModularRouteDelegate(this.navigatorKey, this.parser, this.injectMap); - - NavigatorState get navigator => navigatorKey.currentState!; - - ModularRoute? _router; - - List _pages = []; - - @override - ModularRoute? get currentConfiguration => _router; - ModularRoute get lastPage => _pages.last.router; - - @override - Widget build(BuildContext context) { - return _pages.isEmpty - ? Material() - : Navigator( - key: navigatorKey, - pages: _pages, - onPopPage: _onPopPage, - ); - } - - @override - Future setNewRoutePath(ModularRoute router) async { - final page = ModularPage( - key: ValueKey('url:${router.path}'), - router: router, - ); - if (_pages.isEmpty) { - _pages.add(page); - } else { - _pages.last.completePop(null); - _pages.last = page; - } - _router = router; - - rebuildPages(); - } - - @override - Future navigate(String path, {arguments}) async { - var router = await parser.selectRoute(path); - router = router.copyWith(args: router.args?.copyWith(data: arguments)); - setNewRoutePath(router); - } - - bool _onPopPage(Route route, dynamic result) { - if (!route.didPop(result)) { - return false; - } - - if (route.isFirst) { - rebuildPages(); - return false; - } - - final page = route.settings as ModularPage; - final path = page.router.path; - page.completePop(result); - _pages.removeLast(); - rebuildPages(); - - final trash = []; - - injectMap.forEach((key, module) { - module.paths.remove(path); - if (module.paths.length == 0) { - module.cleanInjects(); - trash.add(key); - Modular.debugPrintModular( - "-- ${module.runtimeType.toString()} DISPOSED"); - } - }); - - for (final key in trash) { - injectMap.remove(key); - } - - return true; - } - - void rebuildPages() { - _pages = List.from(_pages); - notifyListeners(); - } - - @override - Future pushNamed(String routeName, - {Object? arguments}) async { - var router = await parser.selectRoute(routeName); - router = router.copyWith(args: router.args?.copyWith(data: arguments)); - final page = ModularPage( - key: UniqueKey(), - router: router, - ); - _pages.add(page); - rebuildPages(); - return await page.waitPop(); - } - - @override - Future pushReplacementNamed( - String routeName, - {TO? result, - Object? arguments}) async { - var router = await parser.selectRoute(routeName); - router = router.copyWith(args: router.args?.copyWith(data: arguments)); - final page = ModularPage( - key: UniqueKey(), - router: router, - ); - - _pages.last.completePop(result); - _pages.last = page; - rebuildPages(); - return await page.waitPop(); - } - - @override - Future popAndPushNamed( - String routeName, - {TO? result, - Object? arguments}) async { - _pages.last.completePop(result); - _pages.removeLast(); - return await pushNamed(routeName, arguments: arguments); - } - - @override - bool canPop() { - return navigator.canPop(); - } - - @override - Future maybePop([T? result]) => - navigator.maybePop(result); - - @override - void pop([T? result]) => navigator.pop(result); - - @override - void popUntil(bool Function(Route) predicate) => - navigator.popUntil(predicate); - - @override - Future pushNamedAndRemoveUntil( - String newRouteName, bool Function(Route) predicate, - {Object? arguments}) { - popUntil(predicate); - return pushNamed(newRouteName, arguments: arguments); - } - - @override - String get modulePath => _router!.modulePath ?? '/'; - - @override - String get path => _router!.path ?? '/'; - - @override - Future push(Route route) { - return navigator.push(route); - } -} diff --git a/flutter_modular/.src/exceptions/modular_error.dart b/flutter_modular/.src/exceptions/modular_error.dart deleted file mode 100644 index c46792d3..00000000 --- a/flutter_modular/.src/exceptions/modular_error.dart +++ /dev/null @@ -1,10 +0,0 @@ -class ModularError implements Exception { - final String message; - - ModularError(this.message); - - @override - String toString() { - return "ModularError: $message"; - } -} diff --git a/flutter_modular/.src/inject/bind.dart b/flutter_modular/.src/inject/bind.dart deleted file mode 100644 index 91ee65bf..00000000 --- a/flutter_modular/.src/inject/bind.dart +++ /dev/null @@ -1,53 +0,0 @@ -import '../../flutter_modular.dart'; - -class Bind { - final T Function(Inject i) inject; - - ///single instance object? - final bool singleton; - - ///When 'true', the object is instantiated only the first time it is called. - ///When 'false', the object is instantiated along with the module. - final bool lazy; - - Bind(this.inject, {this.singleton = true, this.lazy = true}) - : assert((singleton || lazy), - r"'singleton' can't be false if 'lazy' is also false"); - - ///Bind a 'Singleton' class. - ///Built together with the module. - ///The instance will always be the same. - factory Bind.singleton(T Function(Inject i) inject) { - return Bind(inject, singleton: true, lazy: false); - } - - ///Bind a 'Lazy Singleton' class. - ///Built only when called the first time using Modular.get. - ///The instance will always be the same. - factory Bind.lazySingleton(T Function(Inject i) inject) { - return Bind(inject, singleton: true, lazy: true); - } - - ///Bind a factory. Always a new constructor when calling Modular.get - factory Bind.factory(T Function(Inject i) inject) { - return Bind(inject, singleton: false, lazy: false); - } -} - -class BindInject extends Bind { - final T Function(Inject i) inject; - - ///single instance object? - final bool singleton; - - ///When 'true', the object is instantiated only the first time it is called. - ///When 'false', the object is instantiated along with the module. - final bool lazy; - - BindInject(this.inject, {this.singleton = true, this.lazy = true}) - : super(inject, singleton: singleton, lazy: lazy); -} - -class BindEmpty extends Bind { - BindEmpty() : super((e) => Object()); -} diff --git a/flutter_modular/.src/inject/inject.dart b/flutter_modular/.src/inject/inject.dart deleted file mode 100644 index 08891cff..00000000 --- a/flutter_modular/.src/inject/inject.dart +++ /dev/null @@ -1,36 +0,0 @@ -import '../../flutter_modular.dart'; - -import '../modular_base.dart'; - -class Inject { - ///!!!!NOT RECOMMENDED USE!!!! - ///Bind has access to the arguments coming from the routes. - ///If you need specific access, do it through functions. - @deprecated - Map? params = {}; - final List typesInRequest; - - Inject({this.params, this.typesInRequest = const []}); - - B? call({Map params = const {}, B? defaultValue}) => - get(params: params, defaultValue: defaultValue); - - /// get injected dependency - B? get({Map params = const {}, B? defaultValue}) { - return Modular.get( - params: params, - typesInRequest: typesInRequest, - defaultValue: defaultValue, - ); - } - - void dispose() { - Modular.dispose(); - } -} - -mixin InjectMixinBase { - final Inject _inject = Inject(); - - S? get() => _inject.get(); -} diff --git a/flutter_modular/.src/interfaces/child_module.dart b/flutter_modular/.src/interfaces/child_module.dart deleted file mode 100644 index 6d108dbe..00000000 --- a/flutter_modular/.src/interfaces/child_module.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../flutter_modular.dart'; -import '../routers/modular_router.dart'; - -abstract class ChildModule { - late List _binds; - List get binds; - List get routers; - - ChildModule() { - _binds = binds; - } - - void changeBinds(List b) { - _binds = b; - } - - final List paths = []; - - final Map _singletonBinds = {}; - - T? getBind(Map params, - {required List typesInRequest}) { - T bindValue; - var type = _getInjectType(); - if (_singletonBinds.containsKey(type)) { - bindValue = _singletonBinds[type]; - return bindValue; - } - - var bind = _binds.firstWhere((b) => b.inject is T Function(Inject), - orElse: () => BindEmpty()); - if (bind is BindEmpty) { - typesInRequest.remove(type); - return null; - } - - if (typesInRequest.contains(type)) { - throw ModularError(''' -Recursive calls detected. This can cause StackOverflow. -Check the Binds of the $runtimeType module: -*** -${typesInRequest.join('\n')} -*** - - '''); - } else { - typesInRequest.add(type); - } - - bindValue = - bind.inject(Inject(params: params, typesInRequest: typesInRequest)); - if (bind.singleton) { - _singletonBinds[type] = bindValue; - } - - typesInRequest.remove(type); - return bindValue; - } - - /// Dispose bind from the memory - bool remove() { - final type = _getInjectType(); - if (_singletonBinds.containsKey(type)) { - var inject = _singletonBinds[type]; - _callDispose(inject); - _singletonBinds.remove(type); - return true; - } else { - return false; - } - } - - _callDispose(dynamic bind) { - if (bind is Disposable || bind is ChangeNotifier) { - bind.dispose(); - return; - } else if (bind is Sink) { - bind.close(); - return; - } - } - - /// Dispose all bind from the memory - void cleanInjects() { - for (final key in _singletonBinds.keys) { - var _bind = _singletonBinds[key]; - _callDispose(_bind); - } - _singletonBinds.clear(); - } - - Type _getInjectType() { - var foundType = B; - _singletonBinds.forEach((key, value) { - if (value is B) { - foundType = key; - } - }); - - return foundType; - } - - /// Create a instance of all binds isn't lazy Loaded - void instance() { - for (final bindElement in _binds) { - if (!bindElement.lazy) { - var b = bindElement.inject(Inject()); - _singletonBinds[b.runtimeType] = b; - } - } - } -} diff --git a/flutter_modular/.src/interfaces/disposable.dart b/flutter_modular/.src/interfaces/disposable.dart deleted file mode 100644 index 744d7ef0..00000000 --- a/flutter_modular/.src/interfaces/disposable.dart +++ /dev/null @@ -1,7 +0,0 @@ -/// A class which implements [Disposable] can be disposed automatically -/// once user leaves a Module -//ignore:one_member_abstracts -abstract class Disposable { - /// Disposes controllers, streams, etc. - void dispose(); -} diff --git a/flutter_modular/.src/interfaces/main_module.dart b/flutter_modular/.src/interfaces/main_module.dart deleted file mode 100644 index f3f870d0..00000000 --- a/flutter_modular/.src/interfaces/main_module.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import 'child_module.dart'; - -abstract class MainModule extends ChildModule { - Widget get bootstrap; -} diff --git a/flutter_modular/.src/interfaces/modular_interface.dart b/flutter_modular/.src/interfaces/modular_interface.dart deleted file mode 100644 index 11e37f41..00000000 --- a/flutter_modular/.src/interfaces/modular_interface.dart +++ /dev/null @@ -1,20 +0,0 @@ -import '../../flutter_modular.dart'; - -abstract class ModularInterface { - bool get debugMode; - - String get initialRoute; - ChildModule get initialModule; - void init(ChildModule module); - void bindModule(ChildModule module, [String path]); - void debugPrintModular(String text); - - IModularNavigator get to; - IModularNavigator get link; - B? get({ - Map params = const {}, - List typesInRequest = const [], - B? defaultValue, - }); - void dispose(); -} diff --git a/flutter_modular/.src/interfaces/modular_navigator_interface.dart b/flutter_modular/.src/interfaces/modular_navigator_interface.dart deleted file mode 100644 index 47a50d3f..00000000 --- a/flutter_modular/.src/interfaces/modular_navigator_interface.dart +++ /dev/null @@ -1,104 +0,0 @@ -import 'package:flutter/widgets.dart'; - -abstract class IModularNavigator { - String get path; - String get modulePath; - - /// Navigate to a new screen. - /// - /// ``` - /// Modular.to.push(MaterialPageRoute(builder: (context) => HomePage()),); - /// ``` - Future push(Route route); - - /// Pop the current route off the navigator and navigate to a route. - /// - /// ``` - /// Modular.to.popAndPushNamed('/home'); - /// ``` - /// You could give parameters - /// ``` - /// Modular.to.popAndPushNamed('/home', arguments: 10); - /// ``` - Future popAndPushNamed( - String routeName, - {TO result, - Object arguments}); - - /// Navigate to a route. - /// - /// ``` - /// Modular.to.pushNamed('/home/10'); - /// ``` - /// You could give parameters - /// ``` - /// Modular.to.pushNamed('/home', arguments: 10); - /// ``` - Future pushNamed(String routeName, {Object arguments}); - - /// Push the route with the given name onto the navigator that most tightly - /// encloses the given context, and then remove all the previous routes until - /// the predicate returns true. - /// - /// ``` - /// Modular.to.pushNamedAndRemoveUntil('/home/10', ModalRoute.withName('/')); - /// ``` - /// You could give parameters - /// ``` - /// Modular.to.pushNamedAndRemoveUntil('/home', ModalRoute.withName('/'), arguments: 10); - /// ``` - Future pushNamedAndRemoveUntil( - String newRouteName, bool Function(Route) predicate, - {Object arguments}); - - ///Replace the current route of the navigator that most tightly encloses the - ///given context by pushing the route named routeName and then disposing the - ///previous route once the new route has finished animating in. - /// - /// ``` - /// Modular.to.pushReplacementNamed('/home/10'); - /// ``` - /// You could give parameters - /// ``` - /// Modular.to.pushReplacementNamed('/home', arguments: 10); - /// ``` - Future pushReplacementNamed( - String routeName, - {TO result, - Object arguments}); - - /// Removes the current Route from the stack of routes. - /// - /// ``` - /// Modular.to.pop(); - /// ``` - void pop([T result]); - - /// The initial route cannot be popped off the navigator, which implies that - /// this function returns true only if popping the navigator would not remove - /// the initial route. - /// - /// ``` - /// Modular.to.canPop(); - /// ``` - bool canPop(); - - ///Consults the current route's Route.willPop method, and acts accordingly, - ///potentially popping the route as a result; returns whether the pop request - ///should be considered handled. - /// - /// ``` - /// Modular.to.maybePop(); - /// ``` - Future maybePop([T result]); - - ///Calls pop repeatedly on the navigator that most tightly encloses the given - ///context until the predicate returns true. - /// - /// ``` - /// Modular.to.popUntil(ModalRoute.withName('/login')); - /// ``` - void popUntil(bool Function(Route) predicate); - - void navigate(String path, {dynamic arguments}); -} diff --git a/flutter_modular/.src/interfaces/route_guard.dart b/flutter_modular/.src/interfaces/route_guard.dart deleted file mode 100644 index e36f79f5..00000000 --- a/flutter_modular/.src/interfaces/route_guard.dart +++ /dev/null @@ -1,6 +0,0 @@ -//ignore:one_member_abstracts -import '../routers/modular_router.dart'; - -mixin RouteGuard { - Future canActivate(String path, ModularRoute router); -} diff --git a/flutter_modular/.src/modular_base.dart b/flutter_modular/.src/modular_base.dart deleted file mode 100644 index 5b9393e9..00000000 --- a/flutter_modular/.src/modular_base.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../flutter_modular.dart'; -import 'delegates/modular_route_information_parser.dart'; -import 'delegates/modular_router_delegate.dart'; -import 'interfaces/child_module.dart'; -import 'interfaces/modular_interface.dart'; -import 'modular_impl.dart'; - -final _navigatorKey = GlobalKey(); - -final Map _injectMap = {}; - -final _routeInformationParser = ModularRouteInformationParser(); -final _routerDelegate = ModularRouteDelegate( - _navigatorKey, - _routeInformationParser, - _injectMap, -); - -// ignore: non_constant_identifier_names -final ModularInterface Modular = ModularImpl( - routerDelegate: _routerDelegate, - injectMap: _injectMap, -); - -extension ModularExtension on MaterialApp { - MaterialApp modular() { - final app = MaterialApp.router( - key: key, - // scaffoldMessengerKey: scaffoldMessengerKey, - routeInformationProvider: routeInformationProvider, - backButtonDispatcher: backButtonDispatcher, - builder: builder, - title: title, - onGenerateTitle: onGenerateTitle, - color: color, - theme: theme, - darkTheme: darkTheme, - highContrastTheme: highContrastTheme, - highContrastDarkTheme: highContrastDarkTheme, - themeMode: themeMode, - locale: locale, - localizationsDelegates: localizationsDelegates, - localeListResolutionCallback: localeListResolutionCallback, - localeResolutionCallback: localeResolutionCallback, - supportedLocales: supportedLocales, - debugShowMaterialGrid: debugShowMaterialGrid, - showPerformanceOverlay: showPerformanceOverlay, - checkerboardRasterCacheImages: checkerboardRasterCacheImages, - checkerboardOffscreenLayers: checkerboardOffscreenLayers, - showSemanticsDebugger: showSemanticsDebugger, - debugShowCheckedModeBanner: debugShowCheckedModeBanner, - shortcuts: shortcuts, - actions: actions, - // restorationScopeId: restorationScopeId, - routeInformationParser: _routeInformationParser, - routerDelegate: _routerDelegate, - ); - - return app; - } -} diff --git a/flutter_modular/.src/modular_impl.dart b/flutter_modular/.src/modular_impl.dart deleted file mode 100644 index ece5da30..00000000 --- a/flutter_modular/.src/modular_impl.dart +++ /dev/null @@ -1,133 +0,0 @@ -import 'package:flutter/foundation.dart'; - -import '../flutter_modular.dart'; -import 'delegates/modular_router_delegate.dart'; -import 'interfaces/modular_interface.dart'; - -late ChildModule _initialModule; - -class ModularImpl implements ModularInterface { - final ModularRouteDelegate routerDelegate; - final Map injectMap; - IModularNavigator? navigatorDelegate; - - ModularImpl({ - required this.routerDelegate, - required this.injectMap, - this.navigatorDelegate, - }); - - @override - ChildModule get initialModule => _initialModule; - - @override - void debugPrintModular(String text) { - if (Modular.debugMode) { - debugPrint(text); - } - } - - @override - void bindModule(ChildModule module, [String path = '']) { - final name = module.runtimeType.toString(); - if (!injectMap.containsKey(name)) { - module.paths.add(path); - injectMap[name] = module; - module.instance(); - debugPrintModular("-- ${module.runtimeType.toString()} INITIALIZED"); - } else { - injectMap[name]?.paths.add(path); - } - } - - @override - void init(ChildModule module) { - _initialModule = module; - bindModule(module, "global=="); - } - - @override - IModularNavigator get to => navigatorDelegate ?? routerDelegate; - - @override - IModularNavigator get link => throw UnimplementedError(); - - @override - bool get debugMode => !kReleaseMode; - - @override - String get initialRoute => '/'; - - @override - B get( - {Map params = const {}, - List typesInRequest = const [], - B? defaultValue}) { - if (B.toString() == 'dynamic') { - throw ModularError('not allow for dynamic values'); - } - B? result; - - if (typesInRequest.isEmpty) { - final module = routerDelegate - .currentConfiguration?.currentModule.runtimeType - .toString() ?? - '=global'; - result = _getInjectableObject(module, - params: params, typesInRequest: typesInRequest); - } - - if (result != null) { - return result; - } - - for (var key in injectMap.keys) { - final value = _getInjectableObject(key, - params: params, typesInRequest: typesInRequest, checkKey: false); - if (value != null) { - return value; - } - } - - if (result == null && defaultValue != null) { - return defaultValue; - } - - throw ModularError('${B.toString()} not found'); - } - - B? _getInjectableObject( - String tag, { - Map params = const {}, - List typesInRequest = const [], - bool checkKey = true, - }) { - B? value; - if (!checkKey) { - value = - injectMap[tag]?.getBind(params, typesInRequest: typesInRequest); - } else if (injectMap.containsKey(tag)) { - value = - injectMap[tag]?.getBind(params, typesInRequest: typesInRequest); - } - - return value; - } - - @override - void dispose() { - if (B.toString() == 'dynamic') { - throw ModularError('not allow for dynamic values'); - } - - for (var key in injectMap.keys) { - if (_removeInjectableObject(key)) { - break; - } - } - } - - bool _removeInjectableObject(String tag) { - return injectMap[tag]?.remove() ?? false; - } -} diff --git a/flutter_modular/.src/routers/modular_link.dart b/flutter_modular/.src/routers/modular_link.dart deleted file mode 100644 index 7a6f4301..00000000 --- a/flutter_modular/.src/routers/modular_link.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../delegates/modular_router_delegate.dart'; -import '../interfaces/modular_navigator_interface.dart'; - -class ModularLink implements IModularNavigator { - final ModularRouteDelegate delegate; - - ModularLink(this.delegate); - - @override - bool canPop() => delegate.canPop(); - - @override - Future push(Route route) => delegate.push(route); - - @override - Future maybePop([T? result]) => - delegate.maybePop(result); - - @override - void pop([T? result]) => delegate.pop(result); - - @override - void popUntil(bool Function(Route) predicate) => - delegate.popUntil(predicate); - - @override - String get modulePath => delegate.lastPage.modulePath ?? '/'; - @override - String get path => delegate.lastPage.path ?? '/'; - - @override - void navigate(String path, {arguments}) => delegate.navigate( - modulePath + path, - arguments: arguments, - ); - - @override - Future popAndPushNamed( - String routeName, - {TO? result, - Object? arguments}) { - return delegate.popAndPushNamed( - modulePath + routeName, - result: result, - arguments: arguments, - ); - } - - @override - Future pushNamed(String routeName, {Object? arguments}) { - return delegate.pushNamed( - modulePath + routeName, - arguments: arguments, - ); - } - - @override - Future pushNamedAndRemoveUntil( - String newRouteName, bool Function(Route) predicate, - {Object? arguments}) { - return delegate.pushNamedAndRemoveUntil( - modulePath + newRouteName, - predicate, - arguments: arguments, - ); - } - - @override - Future pushReplacementNamed( - String routeName, - {TO? result, - Object? arguments}) { - return delegate.pushReplacementNamed( - modulePath + routeName, - result: result, - arguments: arguments, - ); - } -} diff --git a/flutter_modular/.src/routers/modular_page.dart b/flutter_modular/.src/routers/modular_page.dart deleted file mode 100644 index 5d079589..00000000 --- a/flutter_modular/.src/routers/modular_page.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -import '../../flutter_modular.dart'; - -final Map _allCompleters = {}; - -class ModularPage extends Page { - final ModularRoute router; - - ModularPage({LocalKey? key, required this.router}) - : super(key: key, name: router.path, arguments: router.args?.data); - - Future waitPop() { - if (_allCompleters.containsKey(hashCode)) { - return (_allCompleters[hashCode] as Completer).future; - } else { - _allCompleters[hashCode] = Completer(); - return (_allCompleters[hashCode] as Completer).future; - } - } - - void completePop(T result) { - if (_allCompleters.containsKey(hashCode) && - !(_allCompleters[hashCode] as Completer).isCompleted) { - (_allCompleters[hashCode] as Completer).complete(result); - _allCompleters.remove(hashCode); - } - } - - @override - Route createRoute(BuildContext context) { - return router.getPageRoute(this); - } - - // @override - // bool operator ==(Object o) { - // if (identical(this, o)) return true; - - // return o is ModularPage && o.router == router; - // } - - // @override - // int get hashCode => router.hashCode; -} - -class ModularRoute extends Route { - final ModularPage page; - - ModularRoute(this.page) : super(settings: page); -} diff --git a/flutter_modular/.src/routers/modular_router.dart b/flutter_modular/.src/routers/modular_router.dart deleted file mode 100644 index af4661d7..00000000 --- a/flutter_modular/.src/routers/modular_router.dart +++ /dev/null @@ -1,346 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import '../../flutter_modular.dart'; -import '../interfaces/child_module.dart'; -import '../interfaces/route_guard.dart'; -import '../transitions/transitions.dart'; -import '../utils/modular_arguments.dart'; - -typedef RouteBuilder = MaterialPageRoute Function( - WidgetBuilder, RouteSettings); -typedef ModularChild = Widget Function( - BuildContext context, ModularArguments? args); - -class ModularRoute { - final ChildModule? currentModule; - - final ModularArguments? args; - - final List children; - - final String? path; - - /// - /// Paramenter name: [routerName] - /// - /// Name for your route - /// - /// Type: String - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final String routerName; - - /// - /// Paramenter name: [child] - /// - /// The widget will be displayed - /// - /// Type: Widget - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - - final ModularChild? child; - - /// - /// Paramenter name: [module] - /// - /// The module will be loaded - /// - /// Type: ChildModule - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final ChildModule? module; - - /// - /// Paramenter name: [params] - /// - /// The parameters that can be transferred to another screen - /// - /// Type: Map - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final Map? params; - - /// - /// Paramenter name: [guards] - /// - /// Route guards are middleware-like objects - /// - /// that allow you to control the access of a given route from other route. - /// - /// You can implement a route guard by making a class that implements RouteGuard. - /// - /// Type: List - /// - /// Example: - /// ```dart - ///class MyGuard implements RouteGuard { - /// @override - /// Future canActivate(String url, ModularRoute router) { - /// if (url != '/admin'){ - /// // Return `true` to allow access - /// return true; - /// } else { - /// // Return `false` to disallow access - /// return false - /// } - /// } - ///} - /// ``` - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - - final List? guards; - - /// - /// Paramenter name: [transition] - /// - /// Used to animate the transition from one screen to another - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final TransitionType transition; - - /// - /// Paramenter name: [customTransiton] - /// - /// PS: For [customTransition] to work, - /// - /// you must set the [transition] parameter for - /// ```dart - /// transition.custom, - /// ``` - /// - /// Example: Using just First Animation - /// ```dart - /// customTransition: CustomTransition( - /// transitionBuilder: (context, animation, secondaryAnimation, child) { - /// return SlideTransition( - /// transformHitTests: false, - /// position: Tween( - /// begin: const Offset(0.0, 1.0), - /// end: Offset.zero, - /// ).chain(CurveTween(curve: Curves.ease)).animate(animation), - /// child: child); - /// }, - /// ), - /// ``` - - /// Example: Using just secondaryAnimation - /// ```dart - /// customTransition: CustomTransition( - /// transitionBuilder: (context, animation, secondaryAnimation, child) { - /// return SlideTransition( - /// transformHitTests: false, - /// position: Tween( - /// begin: const Offset(0.0, 1.0), - /// end: Offset.zero, - /// ).chain(CurveTween(curve: Curves.ease)).animate(animation), - /// child: SlideTransition( - /// transformHitTests: false, - /// position: Tween( - /// begin: Offset.zero, - /// end: const Offset(0.0, -1.0), - /// ).chain(CurveTween(curve: Curves.ease)).animate(secondaryAnimation), - /// child: child, - /// ), - /// ); - /// }, - /// ), - /// ``` - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final CustomTransition? customTransition; - - /// - /// Paramenter name: [transition] - /// - /// Used to animate the transition from one screen to another - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final RouteBuilder? routeGenerator; - final String? modulePath; - final Duration duration; - final Map< - TransitionType, - PageRouteBuilder Function( - Widget Function(BuildContext, ModularArguments?) builder, - ModularArguments? args, - Duration transitionDuration, - RouteSettings settings, - )> transitions = { - TransitionType.fadeIn: fadeInTransition, - TransitionType.noTransition: noTransition, - TransitionType.rightToLeft: rightToLeft, - TransitionType.leftToRight: leftToRight, - TransitionType.upToDown: upToDown, - TransitionType.downToUp: downToUp, - TransitionType.scale: scale, - TransitionType.rotate: rotate, - TransitionType.size: size, - TransitionType.rightToLeftWithFade: rightToLeftWithFade, - TransitionType.leftToRightWithFade: leftToRightWithFade, - }; - - ModularRoute( - this.routerName, { - this.path = '/', - this.children = const [], - this.args = const ModularArguments(), - this.module, - this.child, - this.guards, - this.params, - this.currentModule, - this.transition = TransitionType.defaultTransition, - this.routeGenerator, - this.customTransition, - this.duration = const Duration(milliseconds: 300), - this.modulePath = '/', - }) : assert((transition == TransitionType.custom && - customTransition != null) || - transition != TransitionType.custom && customTransition == null), - assert((module == null && child != null) || - (module != null && child == null)), - assert(module == null ? true : children.isEmpty, - 'Módulo não pode conter rotas aninhadas (children)'); - - ModularRoute copyWith( - {ModularChild? child, - String? routerName, - ChildModule? module, - List? children, - ChildModule? currentModule, - Map? params, - List? guards, - TransitionType? transition, - RouteBuilder? routeGenerator, - String? modulePath, - String? path, - Duration? duration, - Completer? popRoute, - ModularArguments? args, - CustomTransition? customTransition}) { - return ModularRoute( - routerName ?? this.routerName, - child: child ?? this.child, - args: args ?? this.args, - children: children ?? this.children, - module: module ?? this.module, - currentModule: currentModule ?? this.currentModule, - params: params ?? this.params, - modulePath: modulePath ?? this.modulePath, - path: path ?? this.path, - guards: guards ?? this.guards, - duration: duration ?? this.duration, - routeGenerator: routeGenerator ?? this.routeGenerator, - transition: transition ?? this.transition, - customTransition: customTransition ?? this.customTransition, - ); - } - - static List group({ - required List routes, - List? guards, - TransitionType? transition, - CustomTransition? customTransition, - }) { - return routes.map((r) { - return r.copyWith( - guards: guards, - transition: transition ?? r.transition, - customTransition: customTransition ?? r.customTransition, - ); - }).toList(); - } - - Route getPageRoute(RouteSettings settings) { - if (transition == TransitionType.custom && customTransition != null) { - return PageRouteBuilder( - pageBuilder: (context, _, __) { - if (child != null) { - return child!(context, args); - } else { - throw ModularError('Child not be null'); - } - }, - settings: settings, - transitionsBuilder: customTransition!.transitionBuilder, - transitionDuration: customTransition!.transitionDuration, - ); - } else if (transition == TransitionType.defaultTransition) { - // Helper function - Widget widgetBuilder(BuildContext context) { - //return disposablePage; - return child!(context, args); - } - - if (routeGenerator != null) { - return routeGenerator!(widgetBuilder, settings) as Route; - } - return MaterialPageRoute( - settings: settings, - builder: widgetBuilder, - ); - } else { - var selectTransition = transitions[transition]; - if (selectTransition != null) { - return selectTransition(child!, args, duration, settings) as Route; - } else { - throw ModularError('Page Not Found'); - } - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object o) { - if (identical(this, o)) return true; - - return o is ModularRoute && - o.modulePath == modulePath && - o.routerName == routerName && - o.module == module; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return currentModule.hashCode ^ routerName.hashCode; - } -} - -enum TransitionType { - defaultTransition, - fadeIn, - noTransition, - rightToLeft, - leftToRight, - upToDown, - downToUp, - scale, - rotate, - size, - rightToLeftWithFade, - leftToRightWithFade, - custom, -} - -class CustomTransition { - final Widget Function( - BuildContext, Animation, Animation, Widget) - transitionBuilder; - final Duration transitionDuration; - - CustomTransition( - {required this.transitionBuilder, - this.transitionDuration = const Duration(milliseconds: 300)}); -} diff --git a/flutter_modular/.src/test/modular_test_interface.dart b/flutter_modular/.src/test/modular_test_interface.dart deleted file mode 100644 index 7ce7ce46..00000000 --- a/flutter_modular/.src/test/modular_test_interface.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/material.dart'; -import '../../flutter_modular.dart'; -import '../../flutter_modular_test.dart'; - -enum ModularTestType { resetModules, keepModulesOnMemory } - -abstract class IModularTest { - final ModularTestType modularTestType; - IModularTest({this.modularTestType = ModularTestType.resetModules}); - - ChildModule get module; - List get binds; - IModularTest get modulardependency; - - void load({ - IModularTest? changedependency, - List? changeBinds, - bool isLoadDependency = true, - }) { - final dependency = getDendencies( - changedependency: changedependency, - isLoadDependency: isLoadDependency, - ); - final binds = getBinds(changeBinds); - memoryManage(modularTestType); - loadModularDependency( - isLoadDependency: isLoadDependency, - changeBinds: changeBinds, - dependency: dependency, - ); - - initModule(module, changeBinds: binds, initialModule: isMainModule); - } - - @visibleForTesting - IModularTest getDendencies({ - IModularTest? changedependency, - required bool isLoadDependency, - }) { - changedependency ??= modulardependency; - - assert( - !_isDependencyRequired(changedependency, isLoadDependency), - "Dependency must not be null when isLoadDependency is true", - ); - return changedependency; - } - - bool _isDependencyRequired(IModularTest? dependency, bool isLoadDependency) => - dependency == null && isLoadDependency && isMainModule; - - @visibleForTesting - List getBinds(List? changeBinds) { - final mergedChangeBinds = mergeBinds(changeBinds, binds); - - return mergedChangeBinds; - } - - @visibleForTesting - List mergeBinds(List? changeBinds, List? defaultBinds) { - final resultBinds = defaultBinds ?? []; - - for (var bind in (changeBinds ?? [])) { - var changedBind = resultBinds.firstWhere( - (item) => item.runtimeType == bind.runtimeType, - orElse: () => BindEmpty(), - ); - - if (changedBind is! BindEmpty) resultBinds.remove(changedBind); - resultBinds.add(bind); - } - - return resultBinds; - } - - @visibleForTesting - void memoryManage(ModularTestType modularTestType) { - if (modularTestType == ModularTestType.resetModules) { - // Modular.removeModule(module); - } - } - - @visibleForTesting - void loadModularDependency({ - required bool isLoadDependency, - required List? changeBinds, - required IModularTest? dependency, - }) { - if (isLoadDependency && dependency != null) { - dependency.load(changeBinds: changeBinds); - } - } - - bool get isMainModule => !(module is MainModule); -} diff --git a/flutter_modular/.src/test/utils_test.dart b/flutter_modular/.src/test/utils_test.dart deleted file mode 100644 index 981eee22..00000000 --- a/flutter_modular/.src/test/utils_test.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../flutter_modular.dart'; - -void initModule(ChildModule module, - {List changeBinds = const [], bool initialModule = false}) { - //Modular.debugMode = false; - final list = module.binds; - final changedList = List.from(list); - for (var item in list) { - var dep = (changeBinds).firstWhere((dep) { - return item.runtimeType == dep.runtimeType; - }, orElse: () => BindEmpty()); - if (dep is BindEmpty) { - changedList.remove(item); - changedList.add(dep); - } - } - module.changeBinds(changedList); - if (initialModule) { - // Modular.init(module); - } else { - // Modular.bindModule(module); - } -} - -void initModules(List modules, - {List changeBinds = const []}) { - for (var module in modules) { - initModule(module, changeBinds: changeBinds); - } -} - -Widget buildTestableWidget(Widget widget) { - return MediaQuery( - data: MediaQueryData(), - child: MaterialApp( - home: widget, - initialRoute: '/', - // navigatorKey: Modular.navigatorKey, - // onGenerateRoute: Modular.generateRoute, - ), - ); -} diff --git a/flutter_modular/.src/utils/modular_arguments.dart b/flutter_modular/.src/utils/modular_arguments.dart deleted file mode 100644 index 169a52a2..00000000 --- a/flutter_modular/.src/utils/modular_arguments.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/foundation.dart'; - -class ModularArguments { - final Map? params; - final dynamic? data; - - const ModularArguments({this.params, this.data}); - - ModularArguments copyWith({Map? params, dynamic? data}) { - return ModularArguments( - params: params ?? this.params, data: data ?? this.data); - } - - factory ModularArguments.empty() { - return ModularArguments(); - } -} diff --git a/flutter_modular/.src/widgets/modular_app.dart b/flutter_modular/.src/widgets/modular_app.dart deleted file mode 100644 index f0354faa..00000000 --- a/flutter_modular/.src/widgets/modular_app.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../../flutter_modular.dart'; -import '../interfaces/main_module.dart'; - -class ModularApp extends StatefulWidget { - final MainModule module; - - ModularApp({ - Key? key, - required this.module, - }) : super(key: key); - - @override - _ModularAppState createState() => _ModularAppState(); -} - -class _ModularAppState extends State { - @override - void initState() { - super.initState(); - Modular.init(widget.module); - } - - @override - void dispose() { - widget.module.cleanInjects(); - if (Modular.debugMode) { - debugPrint("-- ${widget.module.runtimeType.toString()} DISPOSED"); - } - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return widget.module.bootstrap; - } -} diff --git a/flutter_modular/.src/widgets/modular_state.dart b/flutter_modular/.src/widgets/modular_state.dart deleted file mode 100644 index 8fc7dffe..00000000 --- a/flutter_modular/.src/widgets/modular_state.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../flutter_modular.dart'; - -abstract class ModularState - extends State { - final TBind? controller = Modular.get(); - - @override - void dispose() { - super.dispose(); - Modular.dispose(); - } -} diff --git a/flutter_modular/.src/widgets/router_outlet.dart b/flutter_modular/.src/widgets/router_outlet.dart deleted file mode 100644 index c4f36f57..00000000 --- a/flutter_modular/.src/widgets/router_outlet.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../flutter_modular.dart'; -import 'widget_module.dart'; - -class RouterOutlet extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Container(); - // return Router( - // routerDelegate: null, - // ); - } -} - -// class RouterOutlet extends StatefulWidget { -// final ChildModule module; -// final String initialRoute; -// final Key navigatorKey; -// final bool keepAlive; -// final void Function(String route) onChangeRoute; - -// RouterOutlet({ -// Key key, -// @required this.module, -// this.navigatorKey, -// this.initialRoute = '/', -// this.keepAlive = true, -// this.onChangeRoute, -// }) : super(key: key) { -// module.paths.add(runtimeType.toString()); -// } - -// @override -// _RouterOutletState createState() => _RouterOutletState(); -// } - -// class _RouterOutletState extends State -// with AutomaticKeepAliveClientMixin { -// GlobalKey _key; -// @override -// void initState() { -// super.initState(); -// // _key = widget.navigatorKey ?? -// // Modular.outletNavigatorKey(widget.module.runtimeType.toString()); -// } - -// @override -// Widget build(BuildContext context) { -// super.build(context); -// return WillPopScope( -// onWillPop: () async { -// return !await _key.currentState.maybePop(); -// }, -// child: ModularProvider( -// module: widget.module, -// child: Navigator( -// key: _key, -// initialRoute: widget.initialRoute, -// // onGenerateRoute: (setting) { -// // return Modular.generateRoute( -// // setting, widget.module, widget.onChangeRoute); -// // }, -// ), -// ), -// ); -// } - -// @override -// bool get wantKeepAlive => widget.keepAlive; -// } diff --git a/flutter_modular/.src/widgets/widget_module.dart b/flutter_modular/.src/widgets/widget_module.dart deleted file mode 100644 index 2b2cdf08..00000000 --- a/flutter_modular/.src/widgets/widget_module.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:flutter/widgets.dart'; -import '../../flutter_modular.dart'; - -_debugPrintModular(String text) { - if (Modular.debugMode) { - debugPrint(text); - } -} - -abstract class WidgetModule extends StatelessWidget implements ChildModule { - @override - List get binds; - - Widget get view; - - final _FakeModule _fakeModule = _FakeModule(); - - WidgetModule() { - _fakeModule.changeBinds(binds); - } - - @override - void changeBinds(List b) { - _fakeModule.changeBinds(b); - } - - @override - void cleanInjects() { - _fakeModule.cleanInjects(); - } - - @override - T? getBind(Map params, - {List typesInRequest = const []}) { - return _fakeModule.getBind(params, typesInRequest: typesInRequest); - } - - @override - List get paths => [runtimeType.toString()]; - - @override - bool remove() { - return _fakeModule.remove(); - } - - @override - void instance() { - _fakeModule.instance(); - } - - @override - List get routers => const []; - - @override - Widget build(BuildContext context) { - return ModularProvider( - module: this, - child: view, - ); - } -} - -class _FakeModule extends ChildModule { - final List? bindsInject; - - _FakeModule({this.bindsInject}) { - paths.add(runtimeType.toString()); - } - - @override - List get binds => bindsInject ?? []; - - @override - List get routers => []; -} - -class ModularProvider extends StatefulWidget { - final ChildModule module; - final Widget child; - - const ModularProvider({Key? key, required this.module, required this.child}) - : super(key: key); - - @override - _ModularProviderState createState() => _ModularProviderState(); -} - -class _ModularProviderState extends State { - @override - void initState() { - super.initState(); - // Modular.addCoreInit(widget.module); - _debugPrintModular("-- ${widget.module.runtimeType} INITIALIZED"); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } - - @override - void dispose() { - super.dispose(); - // Modular.removeModule(widget.module); - _debugPrintModular("-- ${widget.module.runtimeType} DISPOSED"); - } -} diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index 3ad5fa62..23daa56b 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -68,6 +68,8 @@ class RouterOutlet extends StatefulWidget { class _RouterOutletState extends State { late GlobalKey navigatorKey; late RouterOutletDelegate delegate; + ChildBackButtonDispatcher? _backButtonDispatcher; + @override void initState() { super.initState(); @@ -75,10 +77,19 @@ class _RouterOutletState extends State { delegate = RouterOutletDelegate(_routerDelegate, navigatorKey); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final router = Router.of(context); + _backButtonDispatcher = + router.backButtonDispatcher?.createChildBackButtonDispatcher(); + } + @override Widget build(BuildContext context) { return Router( routerDelegate: delegate, + backButtonDispatcher: _backButtonDispatcher, ); } } diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index e1039eea..7f3f8ac1 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_modular/src/core/models/modular_route.dart'; +import '../../core/models/modular_route.dart'; import '../../core/modules/child_module.dart'; import '../interfaces/modular_navigator_interface.dart'; From 8a1fb479cae18a8c2ebc8259a7c837e27f57dac0 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Thu, 10 Dec 2020 23:30:49 -0300 Subject: [PATCH 57/71] added back button --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 29572fa5..1db19be6 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.10 +version: 3.0.0-nullsafety.11 homepage: https://github.com/Flutterando/modular environment: From ac7f0c3af916110ee2c8c2e3668b22e26600f08d Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 12 Dec 2020 14:35:01 -0300 Subject: [PATCH 58/71] fix physic back button --- .../lib/src/presenters/modular_base.dart | 5 +++-- .../navigation/modular_router_delegate.dart | 17 +++++++++-------- .../navigation/router_outlet_delegate.dart | 2 ++ flutter_modular/pubspec.yaml | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index 23daa56b..cdab2fac 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -68,7 +68,7 @@ class RouterOutlet extends StatefulWidget { class _RouterOutletState extends State { late GlobalKey navigatorKey; late RouterOutletDelegate delegate; - ChildBackButtonDispatcher? _backButtonDispatcher; + late ChildBackButtonDispatcher _backButtonDispatcher; @override void initState() { @@ -82,11 +82,12 @@ class _RouterOutletState extends State { super.didChangeDependencies(); final router = Router.of(context); _backButtonDispatcher = - router.backButtonDispatcher?.createChildBackButtonDispatcher(); + router.backButtonDispatcher!.createChildBackButtonDispatcher(); } @override Widget build(BuildContext context) { + _backButtonDispatcher.takePriority(); return Router( routerDelegate: delegate, backButtonDispatcher: _backButtonDispatcher, diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index 7f3f8ac1..1ced6b6a 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../core/models/modular_route.dart'; @@ -20,14 +21,7 @@ class ModularRouterDelegate extends RouterDelegate final ModularRouteInformationParser parser; final Map injectMap; - ModularRouterDelegate(this.parser, this.injectMap) { - SystemChannels.navigation.setMethodCallHandler((call) async { - if ('pushRouteInformation' == call.method) { - navigate(call.arguments['location']); - } - }); - } - + ModularRouterDelegate(this.parser, this.injectMap); NavigatorState get navigator => navigatorKey.currentState!; List _pages = []; @@ -100,6 +94,13 @@ class ModularRouterDelegate extends RouterDelegate rebuildPages(); } + // @override + // Future popRoute() { + // return SynchronousFuture(true); + + // // return navigator.maybePop(); + // } + bool _onPopPage(Route route, dynamic result) { if (!route.didPop(result)) { return false; diff --git a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart index 74356306..d33bb282 100644 --- a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart @@ -41,8 +41,10 @@ class RouterOutletDelegate extends RouterDelegate return pages.isEmpty ? Material() : CustomNavigator( + key: navigatorKey, pages: _getPages(), onPopPage: (route, result) { + print('Route outlet: $result'); if (pages.length > 1) { final page = route.settings as ModularPage; final path = page.router.path; diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 1db19be6..33c2bbcc 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.11 +version: 3.0.0-nullsafety.12 homepage: https://github.com/Flutterando/modular environment: From b2cac12777e657ecfc5d7c5c952cdaac5fc6897c Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 12 Dec 2020 15:32:14 -0300 Subject: [PATCH 59/71] fix url routing --- .../navigation/modular_router_delegate.dart | 14 ++++++-------- flutter_modular/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index 1ced6b6a..45acf8ef 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -63,9 +63,13 @@ class ModularRouterDelegate extends RouterDelegate _pages = [page]; } - if (execRebuild) { - rebuildPages(); + if (router.routerOutlet.isNotEmpty) { + routerOutlatPages[router.path!] = router.routerOutlet + .map((e) => ModularPage(key: ValueKey(e.path), router: e)) + .toList(); } + + rebuildPages(); } String resolverPath(String routeName, String path) { @@ -86,12 +90,6 @@ class ModularRouterDelegate extends RouterDelegate await parser.selectRoute(linked ? modulePath + routeName : routeName); router = router.copyWith(args: router.args?.copyWith(data: arguments)); setNewRoutePath(router, false); - if (router.routerOutlet.isNotEmpty) { - routerOutlatPages[router.path!] = router.routerOutlet - .map((e) => ModularPage(key: ValueKey(e.path), router: e)) - .toList(); - } - rebuildPages(); } // @override diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 33c2bbcc..c9160659 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.12 +version: 3.0.0-nullsafety.13 homepage: https://github.com/Flutterando/modular environment: From 6b79bfe6dd7ff742bac7c32766682037b185c5a0 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sat, 12 Dec 2020 21:40:00 -0300 Subject: [PATCH 60/71] created childroute and moduleroute --- flutter_modular/example | 1 + flutter_modular/lib/flutter_modular.dart | 3 ++- .../lib/src/core/models/child_route.dart | 23 +++++++++++++++++++ .../lib/src/core/models/module_route.dart | 20 ++++++++++++++++ .../lib/src/core/modules/child_module.dart | 2 +- .../modular_route_information_parser.dart | 8 +++---- .../navigation/router_outlet_delegate.dart | 1 - .../modular_route_information_parse_test.dart | 2 +- modular.code-workspace | 2 +- 9 files changed, 53 insertions(+), 9 deletions(-) create mode 160000 flutter_modular/example create mode 100644 flutter_modular/lib/src/core/models/child_route.dart create mode 100644 flutter_modular/lib/src/core/models/module_route.dart diff --git a/flutter_modular/example b/flutter_modular/example new file mode 160000 index 00000000..9d4a8ce7 --- /dev/null +++ b/flutter_modular/example @@ -0,0 +1 @@ +Subproject commit 9d4a8ce71ac7953e7bd5574dc701b741e34a840d diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index b618418a..7e21eba1 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -5,8 +5,9 @@ export 'src/core/inject/bind.dart'; export 'src/core/inject/inject.dart'; export 'src/core/interfaces/disposable.dart'; export 'src/core/interfaces/route_guard.dart'; +export 'src/core/models/child_route.dart'; export 'src/core/models/modular_arguments.dart'; -export 'src/core/models/modular_route.dart'; +export 'src/core/models/module_route.dart'; export 'src/core/modules/child_module.dart'; export 'src/core/modules/main_module.dart'; export 'src/presenters/modular_base.dart'; diff --git a/flutter_modular/lib/src/core/models/child_route.dart b/flutter_modular/lib/src/core/models/child_route.dart new file mode 100644 index 00000000..01b96a81 --- /dev/null +++ b/flutter_modular/lib/src/core/models/child_route.dart @@ -0,0 +1,23 @@ +import 'package:flutter/widgets.dart'; +import '../interfaces/route_guard.dart'; + +import 'modular_arguments.dart'; +import 'modular_route.dart'; + +class ChildRoute extends ModularRoute { + ChildRoute( + String routerName, { + List children = const [], + required Widget Function(BuildContext, ModularArguments?) child, + List? guards, + TransitionType transition = TransitionType.defaultTransition, + CustomTransition? customTransition, + Duration duration = const Duration(milliseconds: 300), + }) : super(routerName, + duration: duration, + child: child, + customTransition: customTransition, + children: children, + guards: guards, + transition: transition); +} diff --git a/flutter_modular/lib/src/core/models/module_route.dart b/flutter_modular/lib/src/core/models/module_route.dart new file mode 100644 index 00000000..40a9ed8e --- /dev/null +++ b/flutter_modular/lib/src/core/models/module_route.dart @@ -0,0 +1,20 @@ +import '../interfaces/route_guard.dart'; +import '../modules/child_module.dart'; + +import 'modular_route.dart'; + +class ModuleRoute extends ModularRoute { + ModuleRoute( + String routerName, { + required ChildModule module, + List? guards, + TransitionType transition = TransitionType.defaultTransition, + CustomTransition? customTransition, + Duration duration = const Duration(milliseconds: 300), + }) : super(routerName, + duration: duration, + module: module, + customTransition: customTransition, + guards: guards, + transition: transition); +} diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/modules/child_module.dart index 8598ff1c..686936e2 100644 --- a/flutter_modular/lib/src/core/modules/child_module.dart +++ b/flutter_modular/lib/src/core/modules/child_module.dart @@ -9,7 +9,7 @@ import '../models/modular_route.dart'; @immutable abstract class ChildModule { late final List binds; - late final List routers; + late final List routes; @visibleForTesting void changeBinds(List b) { diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 61d7c754..f90b1e93 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -28,7 +28,7 @@ class ModularRouteInformationParser ChildModule module, String routerName, String path) { path = "/$path".replaceAll('//', '/'); final routers = - module.routers.map((e) => e.copyWith(currentModule: module)).toList(); + module.routes.map((e) => e.copyWith(currentModule: module)).toList(); routers.sort((preview, actual) { return preview.routerName.contains('/:') ? 1 : 0; }); @@ -45,7 +45,7 @@ class ModularRouteInformationParser ModularRoute route, String routerName, String path) { ModularRoute? router; if (routerName == path || routerName == "$path/") { - router = route.module!.routers[0]; + router = route.module!.routes[0]; if (router.module != null) { var _routerName = (routerName + route.routerName).replaceFirst('//', '/'); @@ -200,8 +200,8 @@ class ModularRouteInformationParser ? route.children.last : null; } else { - finded = route.currentModule?.routers.last.routerName == '**' - ? route.currentModule?.routers.last + finded = route.currentModule?.routes.last.routerName == '**' + ? route.currentModule?.routes.last : null; } route.currentModule?.paths.remove(localPath); diff --git a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart index d33bb282..7d728916 100644 --- a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart @@ -44,7 +44,6 @@ class RouterOutletDelegate extends RouterDelegate key: navigatorKey, pages: _getPages(), onPopPage: (route, result) { - print('Route outlet: $result'); if (pages.length > 1) { final page = route.settings as ModularPage; final path = page.router.path; diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index cdbfb6ef..f2038d32 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -1,9 +1,9 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; +import 'package:flutter_modular/src/core/models/modular_route.dart'; import 'package:flutter_modular/src/presenters/navigation/modular_route_information_parser.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/modular.code-workspace b/modular.code-workspace index 09567775..2aaee144 100644 --- a/modular.code-workspace +++ b/modular.code-workspace @@ -8,6 +8,6 @@ } ], "settings": { - "dart.flutterSdkPath": "/Users/jacobmoura/fvm/versions/beta" + "dart.flutterSdkPath": "/Users/jacobmoura/fvm/versions/master" } } \ No newline at end of file From df937a6e51cf47a47462ed571c3c7107a54d615f Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 13 Dec 2020 13:50:50 -0300 Subject: [PATCH 61/71] optization --- flutter_modular/lib/flutter_modular.dart | 3 + .../modular_route.dart} | 127 ++++-------------- .../lib/src/core/interfaces/route_guard.dart | 2 +- .../lib/src/core/models/child_route.dart | 8 +- .../src/core/models/custom_transition.dart | 12 ++ ...lar_route.dart => modular_route_impl.dart} | 91 ++++--------- .../lib/src/core/models/module_route.dart | 7 +- .../lib/src/core/models/wildcard.dart | 24 ++++ .../lib/src/core/modules/child_module.dart | 6 +- .../interfaces/modular_interface.dart | 3 +- .../lib/src/presenters/modular_impl.dart | 6 +- .../presenters/navigation/modular_page.dart | 5 +- .../modular_route_information_parser.dart | 4 +- .../navigation/modular_router_delegate.dart | 3 +- .../navigation/router_outlet_delegate.dart | 2 +- .../src/presenters/widgets/widget_module.dart | 13 +- .../lib/src/test/modular_test_interface.dart | 6 +- flutter_modular/lib/src/test/utils_test.dart | 5 +- .../src/core/models/modular_router_test.dart | 16 ++- .../src/core/modules/child_module_test.dart | 6 +- .../modular_route_information_parse_test.dart | 54 ++++---- 21 files changed, 165 insertions(+), 238 deletions(-) rename flutter_modular/lib/src/core/{models/modular_router.dart => interfaces/modular_route.dart} (57%) create mode 100644 flutter_modular/lib/src/core/models/custom_transition.dart rename flutter_modular/lib/src/core/models/{modular_route.dart => modular_route_impl.dart} (85%) create mode 100644 flutter_modular/lib/src/core/models/wildcard.dart diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 7e21eba1..13f405f5 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -4,10 +4,13 @@ export 'flutter_modular_annotations.dart'; export 'src/core/inject/bind.dart'; export 'src/core/inject/inject.dart'; export 'src/core/interfaces/disposable.dart'; +export 'src/core/interfaces/modular_route.dart'; export 'src/core/interfaces/route_guard.dart'; export 'src/core/models/child_route.dart'; +export 'src/core/models/custom_transition.dart'; export 'src/core/models/modular_arguments.dart'; export 'src/core/models/module_route.dart'; +export 'src/core/models/wildcard.dart'; export 'src/core/modules/child_module.dart'; export 'src/core/modules/main_module.dart'; export 'src/presenters/modular_base.dart'; diff --git a/flutter_modular/lib/src/core/models/modular_router.dart b/flutter_modular/lib/src/core/interfaces/modular_route.dart similarity index 57% rename from flutter_modular/lib/src/core/models/modular_router.dart rename to flutter_modular/lib/src/core/interfaces/modular_route.dart index 4ec97168..2fffb092 100644 --- a/flutter_modular/lib/src/core/models/modular_router.dart +++ b/flutter_modular/lib/src/core/interfaces/modular_route.dart @@ -1,28 +1,23 @@ import 'dart:async'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; -import '../interfaces/route_guard.dart'; +import '../models/custom_transition.dart'; +import '../models/modular_arguments.dart'; +import '../models/modular_route_impl.dart'; import '../modules/child_module.dart'; -import '../transitions/transitions.dart'; -import 'modular_arguments.dart'; +import 'route_guard.dart'; -typedef RouteBuilder = MaterialPageRoute Function( - WidgetBuilder, RouteSettings); -typedef ModularChild = Widget Function( - BuildContext context, ModularArguments? args); +abstract class ModularRoute { + ChildModule? get currentModule; -class ModularRoute { - final ChildModule? currentModule; + ModularArguments? get args; - final ModularArguments? args; + List get children; - final List children; + final List routerOutlet = []; - final List routerOutlet; - - final String? path; + String? get path; /// /// Paramenter name: [routerName] @@ -33,7 +28,7 @@ class ModularRoute { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final String routerName; + String get routerName; /// /// Paramenter name: [child] @@ -45,7 +40,7 @@ class ModularRoute { /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final ModularChild? child; + ModularChild? get child; /// /// Paramenter name: [module] @@ -56,7 +51,7 @@ class ModularRoute { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final ChildModule? module; + ChildModule? get module; /// /// Paramenter name: [params] @@ -67,7 +62,7 @@ class ModularRoute { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final Map? params; + Map? get params; /// /// Paramenter name: [guards] @@ -98,7 +93,7 @@ class ModularRoute { /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final List? guards; + List? get guards; /// /// Paramenter name: [transition] @@ -107,7 +102,7 @@ class ModularRoute { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final TransitionType transition; + TransitionType get transition; /// /// Paramenter name: [customTransiton] @@ -158,63 +153,18 @@ class ModularRoute { /// ``` /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - final CustomTransition? customTransition; - - /// - /// Paramenter name: [transition] - /// - /// Used to animate the transition from one screen to another - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final RouteBuilder? routeGenerator; - final String? modulePath; - final Duration duration; - final Map< + CustomTransition? get customTransition; + String? get modulePath; + Duration get duration; + RouteBuilder? get routeGenerator; + Map< TransitionType, PageRouteBuilder Function( Widget Function(BuildContext, ModularArguments?) builder, ModularArguments? args, Duration transitionDuration, RouteSettings settings, - )> transitions = { - TransitionType.fadeIn: fadeInTransition, - TransitionType.noTransition: noTransition, - TransitionType.rightToLeft: rightToLeft, - TransitionType.leftToRight: leftToRight, - TransitionType.upToDown: upToDown, - TransitionType.downToUp: downToUp, - TransitionType.scale: scale, - TransitionType.rotate: rotate, - TransitionType.size: size, - TransitionType.rightToLeftWithFade: rightToLeftWithFade, - TransitionType.leftToRightWithFade: leftToRightWithFade, - }; - - ModularRoute( - this.routerName, { - this.path = '/', - this.children = const [], - this.args = const ModularArguments(), - this.module, - this.child, - this.guards, - this.routerOutlet = const [], - this.params, - this.currentModule, - this.transition = TransitionType.defaultTransition, - this.routeGenerator, - this.customTransition, - this.duration = const Duration(milliseconds: 300), - this.modulePath = '/', - }) : assert(module == null ? true : children.isEmpty, - 'Módulo não pode conter rotas aninhadas (children)'), - assert((transition == TransitionType.custom && - customTransition != null) || - transition != TransitionType.custom && customTransition == null), - assert((module == null && child != null) || - (module != null && child == null)), - assert(routerName == '**' ? child != null : true); + )> get transitions; ModularRoute copyWith( {ModularChild? child, @@ -232,25 +182,7 @@ class ModularRoute { Duration? duration, Completer? popRoute, ModularArguments? args, - CustomTransition? customTransition}) { - return ModularRoute( - routerName ?? this.routerName, - child: child ?? this.child, - args: args ?? this.args, - children: children ?? this.children, - module: module ?? this.module, - routerOutlet: routerOutlet ?? this.routerOutlet, - currentModule: currentModule ?? this.currentModule, - params: params ?? this.params, - modulePath: modulePath ?? this.modulePath, - path: path ?? this.path, - guards: guards ?? this.guards, - duration: duration ?? this.duration, - routeGenerator: routeGenerator ?? this.routeGenerator, - transition: transition ?? this.transition, - customTransition: customTransition ?? this.customTransition, - ); - } + CustomTransition? customTransition}); @override // ignore: avoid_equals_and_hash_code_on_mutable_classes @@ -285,14 +217,3 @@ enum TransitionType { leftToRightWithFade, custom, } - -class CustomTransition { - final Widget Function( - BuildContext, Animation, Animation, Widget) - transitionBuilder; - final Duration transitionDuration; - - CustomTransition( - {required this.transitionBuilder, - this.transitionDuration = const Duration(milliseconds: 300)}); -} diff --git a/flutter_modular/lib/src/core/interfaces/route_guard.dart b/flutter_modular/lib/src/core/interfaces/route_guard.dart index fea976e4..0de7fac3 100644 --- a/flutter_modular/lib/src/core/interfaces/route_guard.dart +++ b/flutter_modular/lib/src/core/interfaces/route_guard.dart @@ -1,6 +1,6 @@ //ignore:one_member_abstracts -import '../models/modular_route.dart'; +import 'modular_route.dart'; // ignore: one_member_abstracts abstract class RouteGuard { diff --git a/flutter_modular/lib/src/core/models/child_route.dart b/flutter_modular/lib/src/core/models/child_route.dart index 01b96a81..02b57c72 100644 --- a/flutter_modular/lib/src/core/models/child_route.dart +++ b/flutter_modular/lib/src/core/models/child_route.dart @@ -1,10 +1,12 @@ import 'package:flutter/widgets.dart'; -import '../interfaces/route_guard.dart'; +import '../interfaces/modular_route.dart'; +import '../interfaces/route_guard.dart'; +import 'custom_transition.dart'; import 'modular_arguments.dart'; -import 'modular_route.dart'; +import 'modular_route_impl.dart'; -class ChildRoute extends ModularRoute { +class ChildRoute extends ModularRouteImpl { ChildRoute( String routerName, { List children = const [], diff --git a/flutter_modular/lib/src/core/models/custom_transition.dart b/flutter_modular/lib/src/core/models/custom_transition.dart new file mode 100644 index 00000000..ed812f59 --- /dev/null +++ b/flutter_modular/lib/src/core/models/custom_transition.dart @@ -0,0 +1,12 @@ +import 'package:flutter/widgets.dart'; + +class CustomTransition { + final Widget Function( + BuildContext, Animation, Animation, Widget) + transitionBuilder; + final Duration transitionDuration; + + CustomTransition( + {required this.transitionBuilder, + this.transitionDuration = const Duration(milliseconds: 300)}); +} diff --git a/flutter_modular/lib/src/core/models/modular_route.dart b/flutter_modular/lib/src/core/models/modular_route_impl.dart similarity index 85% rename from flutter_modular/lib/src/core/models/modular_route.dart rename to flutter_modular/lib/src/core/models/modular_route_impl.dart index 4ec97168..13c5166a 100644 --- a/flutter_modular/lib/src/core/models/modular_route.dart +++ b/flutter_modular/lib/src/core/models/modular_route_impl.dart @@ -2,10 +2,12 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import '../interfaces/modular_route.dart'; import '../interfaces/route_guard.dart'; import '../modules/child_module.dart'; import '../transitions/transitions.dart'; +import 'custom_transition.dart'; import 'modular_arguments.dart'; typedef RouteBuilder = MaterialPageRoute Function( @@ -13,16 +15,19 @@ typedef RouteBuilder = MaterialPageRoute Function( typedef ModularChild = Widget Function( BuildContext context, ModularArguments? args); -class ModularRoute { +class ModularRouteImpl extends ModularRoute { + @override final ChildModule? currentModule; - + @override final ModularArguments? args; - + @override final List children; - + @override final List routerOutlet; - + @override final String? path; + @override + final String? modulePath; /// /// Paramenter name: [routerName] @@ -32,7 +37,7 @@ class ModularRoute { /// Type: String /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// + @override final String routerName; /// @@ -44,7 +49,7 @@ class ModularRoute { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - + @override final ModularChild? child; /// @@ -56,6 +61,7 @@ class ModularRoute { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// + @override final ChildModule? module; /// @@ -67,6 +73,7 @@ class ModularRoute { /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// + @override final Map? params; /// @@ -97,7 +104,7 @@ class ModularRoute { /// ``` /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] /// - + @override final List? guards; /// @@ -106,7 +113,7 @@ class ModularRoute { /// Used to animate the transition from one screen to another /// /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// + @override final TransitionType transition; /// @@ -157,19 +164,16 @@ class ModularRoute { /// ), /// ``` /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// + @override final CustomTransition? customTransition; - /// - /// Paramenter name: [transition] - /// - /// Used to animate the transition from one screen to another - /// - /// For more example go to Modular page from gitHub [https://github.com/Flutterando/modular] - /// - final RouteBuilder? routeGenerator; - final String? modulePath; + @override final Duration duration; + + @override + final RouteBuilder? routeGenerator; + + @override final Map< TransitionType, PageRouteBuilder Function( @@ -191,7 +195,7 @@ class ModularRoute { TransitionType.leftToRightWithFade: leftToRightWithFade, }; - ModularRoute( + ModularRouteImpl( this.routerName, { this.path = '/', this.children = const [], @@ -216,6 +220,7 @@ class ModularRoute { (module != null && child == null)), assert(routerName == '**' ? child != null : true); + @override ModularRoute copyWith( {ModularChild? child, String? routerName, @@ -233,7 +238,7 @@ class ModularRoute { Completer? popRoute, ModularArguments? args, CustomTransition? customTransition}) { - return ModularRoute( + return ModularRouteImpl( routerName ?? this.routerName, child: child ?? this.child, args: args ?? this.args, @@ -251,48 +256,4 @@ class ModularRoute { customTransition: customTransition ?? this.customTransition, ); } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object o) { - if (identical(this, o)) return true; - - return o is ModularRoute && - o.modulePath == modulePath && - o.routerName == routerName && - o.module == module; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return currentModule.hashCode ^ routerName.hashCode; - } -} - -enum TransitionType { - defaultTransition, - fadeIn, - noTransition, - rightToLeft, - leftToRight, - upToDown, - downToUp, - scale, - rotate, - size, - rightToLeftWithFade, - leftToRightWithFade, - custom, -} - -class CustomTransition { - final Widget Function( - BuildContext, Animation, Animation, Widget) - transitionBuilder; - final Duration transitionDuration; - - CustomTransition( - {required this.transitionBuilder, - this.transitionDuration = const Duration(milliseconds: 300)}); } diff --git a/flutter_modular/lib/src/core/models/module_route.dart b/flutter_modular/lib/src/core/models/module_route.dart index 40a9ed8e..410e46cc 100644 --- a/flutter_modular/lib/src/core/models/module_route.dart +++ b/flutter_modular/lib/src/core/models/module_route.dart @@ -1,9 +1,10 @@ +import '../interfaces/modular_route.dart'; import '../interfaces/route_guard.dart'; import '../modules/child_module.dart'; +import 'custom_transition.dart'; +import 'modular_route_impl.dart'; -import 'modular_route.dart'; - -class ModuleRoute extends ModularRoute { +class ModuleRoute extends ModularRouteImpl { ModuleRoute( String routerName, { required ChildModule module, diff --git a/flutter_modular/lib/src/core/models/wildcard.dart b/flutter_modular/lib/src/core/models/wildcard.dart new file mode 100644 index 00000000..3c4bdb27 --- /dev/null +++ b/flutter_modular/lib/src/core/models/wildcard.dart @@ -0,0 +1,24 @@ +import 'package:flutter/widgets.dart'; + +import '../interfaces/modular_route.dart'; +import '../interfaces/route_guard.dart'; +import 'custom_transition.dart'; +import 'modular_arguments.dart'; +import 'modular_route_impl.dart'; + +class WildCard extends ModularRouteImpl { + WildCard({ + List children = const [], + required Widget Function(BuildContext, ModularArguments?) child, + List? guards, + TransitionType transition = TransitionType.defaultTransition, + CustomTransition? customTransition, + Duration duration = const Duration(milliseconds: 300), + }) : super('**', + duration: duration, + child: child, + customTransition: customTransition, + children: children, + guards: guards, + transition: transition); +} diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/modules/child_module.dart index 686936e2..fe3e655e 100644 --- a/flutter_modular/lib/src/core/modules/child_module.dart +++ b/flutter_modular/lib/src/core/modules/child_module.dart @@ -4,12 +4,12 @@ import '../errors/errors.dart'; import '../inject/bind.dart'; import '../inject/inject.dart'; import '../interfaces/disposable.dart'; -import '../models/modular_route.dart'; +import '../interfaces/modular_route.dart'; @immutable abstract class ChildModule { - late final List binds; - late final List routes; + late final List binds = []; + late final List routes = []; @visibleForTesting void changeBinds(List b) { diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart index 7781d85f..bced449c 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart @@ -1,5 +1,4 @@ -import 'package:flutter_modular/flutter_modular.dart'; - +import '../../core/models/modular_arguments.dart'; import '../../core/modules/child_module.dart'; import 'modular_navigator_interface.dart'; diff --git a/flutter_modular/lib/src/presenters/modular_impl.dart b/flutter_modular/lib/src/presenters/modular_impl.dart index 6ef8089f..c84ac97e 100644 --- a/flutter_modular/lib/src/presenters/modular_impl.dart +++ b/flutter_modular/lib/src/presenters/modular_impl.dart @@ -1,8 +1,8 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter_modular/src/core/errors/errors.dart'; -import 'package:flutter_modular/src/core/models/modular_arguments.dart'; -import 'package:flutter_modular/src/core/modules/child_module.dart'; +import '../core/errors/errors.dart'; +import '../core/models/modular_arguments.dart'; +import '../core/modules/child_module.dart'; import 'interfaces/modular_interface.dart'; import 'interfaces/modular_navigator_interface.dart'; import 'modular_base.dart'; diff --git a/flutter_modular/lib/src/presenters/navigation/modular_page.dart b/flutter_modular/lib/src/presenters/navigation/modular_page.dart index 87f7bc7e..34bbb093 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_page.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_page.dart @@ -1,8 +1,9 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/core/errors/errors.dart'; -import '../../core/models/modular_route.dart'; + +import '../../core/errors/errors.dart'; +import '../../core/interfaces/modular_route.dart'; final Map _allCompleters = {}; diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index f90b1e93..566ca699 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; + import '../../core/errors/errors.dart'; -import '../../core/models/modular_route.dart'; +import '../../core/interfaces/modular_route.dart'; import '../../core/modules/child_module.dart'; - import '../modular_base.dart'; class ModularRouteInformationParser diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index 45acf8ef..3d4f0d65 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -1,8 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import '../../core/models/modular_route.dart'; +import '../../core/interfaces/modular_route.dart'; import '../../core/modules/child_module.dart'; import '../interfaces/modular_navigator_interface.dart'; import '../modular_base.dart'; diff --git a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart index 7d728916..5837eab7 100644 --- a/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/router_outlet_delegate.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../core/models/modular_route.dart'; +import '../../core/interfaces/modular_route.dart'; import '../modular_base.dart'; import 'custom_navigator.dart'; import 'modular_page.dart'; diff --git a/flutter_modular/lib/src/presenters/widgets/widget_module.dart b/flutter_modular/lib/src/presenters/widgets/widget_module.dart index 7c36a25f..6f9b1694 100644 --- a/flutter_modular/lib/src/presenters/widgets/widget_module.dart +++ b/flutter_modular/lib/src/presenters/widgets/widget_module.dart @@ -1,8 +1,8 @@ import 'package:flutter/widgets.dart'; + +import '../../../flutter_modular.dart'; import '../../core/inject/bind.dart'; -import '../../core/models/modular_route.dart'; import '../../core/modules/child_module.dart'; - import '../modular_base.dart'; _debugPrintModular(String text) { @@ -11,17 +11,20 @@ _debugPrintModular(String text) { } } +// ignore: must_be_immutable abstract class WidgetModule extends StatelessWidget implements ChildModule { Widget get view; final _FakeModule _fakeModule = _FakeModule(); WidgetModule() { + // ignore: invalid_use_of_visible_for_testing_member _fakeModule.changeBinds(binds); } @override void changeBinds(List b) { + // ignore: invalid_use_of_visible_for_testing_member _fakeModule.changeBinds(b); } @@ -51,7 +54,7 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { } @override - List routers = const []; + List routes = const []; @override Widget build(BuildContext context) { @@ -70,10 +73,10 @@ class _FakeModule extends ChildModule { } @override - List get binds => bindsInject ?? []; + late final List binds = bindsInject ?? []; @override - List get routers => []; + final List routes = []; } class ModularProvider extends StatefulWidget { diff --git a/flutter_modular/lib/src/test/modular_test_interface.dart b/flutter_modular/lib/src/test/modular_test_interface.dart index 0fb7067d..0c649610 100644 --- a/flutter_modular/lib/src/test/modular_test_interface.dart +++ b/flutter_modular/lib/src/test/modular_test_interface.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/core/inject/bind.dart'; -import 'package:flutter_modular/src/core/modules/child_module.dart'; -import 'package:flutter_modular/src/core/modules/main_module.dart'; +import '../core/inject/bind.dart'; +import '../core/modules/child_module.dart'; +import '../core/modules/main_module.dart'; import 'utils_test.dart'; enum ModularTestType { resetModules, keepModulesOnMemory } diff --git a/flutter_modular/lib/src/test/utils_test.dart b/flutter_modular/lib/src/test/utils_test.dart index b143bc6d..dda5da23 100644 --- a/flutter_modular/lib/src/test/utils_test.dart +++ b/flutter_modular/lib/src/test/utils_test.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/core/inject/bind.dart'; -import 'package:flutter_modular/src/core/modules/child_module.dart'; + +import '../core/inject/bind.dart'; +import '../core/modules/child_module.dart'; void initModule(ChildModule module, {List changeBinds = const [], bool initialModule = false}) { diff --git a/flutter_modular/test/src/core/models/modular_router_test.dart b/flutter_modular/test/src/core/models/modular_router_test.dart index 501702bd..e6322fa2 100644 --- a/flutter_modular/test/src/core/models/modular_router_test.dart +++ b/flutter_modular/test/src/core/models/modular_router_test.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter_modular/src/core/models/modular_route.dart'; +import 'package:flutter_modular/src/core/interfaces/modular_route.dart'; +import 'package:flutter_modular/src/core/models/custom_transition.dart'; +import 'package:flutter_modular/src/core/models/modular_route_impl.dart'; import 'package:flutter_test/flutter_test.dart'; import '../modules/child_module_test.dart'; @@ -7,23 +9,23 @@ import '../modules/child_module_test.dart'; main() { test('should initializa in incorrect form', () { expect( - () => ModularRoute('/', + () => ModularRouteImpl('/', child: (context, args) => Container(), module: ModuleMock()), throwsAssertionError); expect( - () => ModularRoute('/', + () => ModularRouteImpl('/', transition: TransitionType.custom, module: ModuleMock()), throwsAssertionError); expect( - () => ModularRoute('/', - children: [ModularRoute('/')], module: ModuleMock()), + () => ModularRouteImpl('/', + children: [ModularRouteImpl('/')], module: ModuleMock()), throwsAssertionError); }); test('should make copy with implementation', () { - final model = ModularRoute('/', module: ModuleMock()); + final model = ModularRouteImpl('/', module: ModuleMock()); final copy = model.copyWith(); expect(copy.module, isA()); final copy2 = model.copyWith(path: '/home'); @@ -34,7 +36,7 @@ main() { }); test('should normal instance custom transition', () { - final model = ModularRoute('/', + final model = ModularRouteImpl('/', transition: TransitionType.custom, module: ModuleMock(), customTransition: CustomTransition(transitionBuilder: (c, a1, a2, w) { return FadeTransition( diff --git a/flutter_modular/test/src/core/modules/child_module_test.dart b/flutter_modular/test/src/core/modules/child_module_test.dart index a4326b3e..43d70d27 100644 --- a/flutter_modular/test/src/core/modules/child_module_test.dart +++ b/flutter_modular/test/src/core/modules/child_module_test.dart @@ -1,15 +1,15 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; import 'package:flutter_modular/src/core/inject/bind.dart'; -import 'package:flutter_modular/src/core/models/modular_route.dart'; import 'package:flutter_modular/src/core/modules/child_module.dart'; import 'package:flutter_test/flutter_test.dart'; class ModuleMock extends ChildModule { @override - List binds = [ + final List binds = [ Bind((i) => "Test"), Bind.instance(1), Bind((i) => true, lazy: false), @@ -18,7 +18,7 @@ class ModuleMock extends ChildModule { ]; @override - List routers = []; + final List routes = []; } main() { diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index f2038d32..dfe72cea 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; -import 'package:flutter_modular/src/core/models/modular_route.dart'; import 'package:flutter_modular/src/presenters/navigation/modular_route_information_parser.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -148,17 +147,17 @@ class ModuleMock extends ChildModule { ]; @override - final List routers = [ - ModularRoute( + final List routes = [ + ChildRoute( '/', child: (context, args) => Container(), ), - ModularRoute( + ChildRoute( '/home', child: (context, args) => Scaffold(), children: [ - ModularRoute('/tab1', child: (context, args) => TextField()), - ModularRoute( + ChildRoute('/tab1', child: (context, args) => TextField()), + ChildRoute( '/tab2/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], @@ -166,22 +165,21 @@ class ModuleMock extends ChildModule { ), ], ), - ModularRoute('/mock', module: ModuleMock2()), - ModularRoute('/guarded', - guards: [MyGuardModule()], module: ModuleGuarded()), - ModularRoute('/list', child: (context, args) => ListView()), - ModularRoute( + ModuleRoute('/mock', module: ModuleMock2()), + ModuleRoute('/guarded', guards: [MyGuardModule()], module: ModuleGuarded()), + ChildRoute('/list', child: (context, args) => ListView()), + ChildRoute( '/401', guards: [MyGuard()], child: (context, args) => SingleChildScrollView(), ), - ModularRoute( + ChildRoute( '/list/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], ), ), - ModularRoute('**', child: (context, args) => FlutterLogo()) + ChildRoute('**', child: (context, args) => FlutterLogo()) ]; } @@ -195,26 +193,26 @@ class ModuleMock2 extends ChildModule { ]; @override - final List routers = [ - ModularRoute('/', child: (context, args) => SizedBox(), children: [ - ModularRoute('/home', child: (context, args) => Container()), + final List routes = [ + ChildRoute('/', child: (context, args) => SizedBox(), children: [ + ChildRoute('/home', child: (context, args) => Container()), ]), - ModularRoute( + ChildRoute( '/list', child: (context, args) => ListView(), ), - ModularRoute( + ChildRoute( '/listguarded', guards: [MyGuard()], child: (context, args) => ListView(), ), - ModularRoute( + ChildRoute( '/list/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], ), ), - ModularRoute('**', child: (context, args) => FlutterLogo()) + ChildRoute('**', child: (context, args) => FlutterLogo()) ]; } @@ -228,27 +226,27 @@ class ModuleGuarded extends ChildModule { ]; @override - final List routers = [ - ModularRoute('/', child: (context, args) => SizedBox(), children: [ - ModularRoute('/home', child: (context, args) => Container()), - ModularRoute('/guarded', child: (context, args) => Container()), + final List routes = [ + ChildRoute('/', child: (context, args) => SizedBox(), children: [ + ChildRoute('/home', child: (context, args) => Container()), + ChildRoute('/guarded', child: (context, args) => Container()), ]), - ModularRoute( + ChildRoute( '/list', child: (context, args) => ListView(), ), - ModularRoute( + ChildRoute( '/listguarded', guards: [MyGuard()], child: (context, args) => ListView(), ), - ModularRoute( + ChildRoute( '/list/:id', child: (context, args) => CustomWidget( text: args?.params!['id'], ), ), - ModularRoute('**', child: (context, args) => FlutterLogo()) + ChildRoute('**', child: (context, args) => FlutterLogo()) ]; } From b2710e317dbb983070b0a6ba5931a46f16581d54 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 13 Dec 2020 17:23:26 -0300 Subject: [PATCH 62/71] fix name of class --- flutter_modular/README.md | 176 +++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/flutter_modular/README.md b/flutter_modular/README.md index 4dc51ac7..75281f9a 100644 --- a/flutter_modular/README.md +++ b/flutter_modular/README.md @@ -110,12 +110,12 @@ class AppModule extends MainModule { // Provide all the routes for your module @override - final List routers = []; + final List routes = []; // Provide the root widget associated with your module // In this case, it's the widget you created in the first step @override - final Widget bootstrap => AppWidget(); + final Widget bootstrap = AppWidget(); } ``` @@ -136,21 +136,17 @@ void main() => runApp(ModularApp(module: AppModule())); ## Adding routes -The module routes are provided by overriding the `routers`: +The module routes are provided by overriding the `routes` property. ```dart // app_module.dart class AppModule extends MainModule { - // Provide a list of dependencies to inject into your project - @override - final List binds = []; - // Provide all the routes for your module @override - final List routers = [ - ModularRoute('/', child: (_, __) => HomePage()), - ModularRoute('/login', child: (_, __) => LoginPage()), + final List routes = [ + ChildRoute('/', child: (_, __) => HomePage()), + ChildRoute('/login', child: (_, __) => LoginPage()), ]; // Provide the root widget associated with your module @@ -159,6 +155,8 @@ class AppModule extends MainModule { } ``` +> **NOTE:** Use the ChildRoute object to create a simple route. + To navigate between pages, use `Modular.to.navigate`. ```dart @@ -202,8 +200,8 @@ You can use dynamic routing system to provide parameters to your `Route`: // using square brackets notation (['parameter_name']). @override -finalList routers = [ - ModularRoute( +final List routes = [ + ChildRoute( '/product/:id', child: (_, args) => Product(id: args.params['id']), ), @@ -227,14 +225,82 @@ And it will be available in the `args.data` property instead of `args.params`: ```dart @override -final List routers = [ - ModularRoute( +final List routes = [ + ChildRoute( '/product', child: (_, args) => Product(model: args.data), ), ]; ``` +## Route generic types + +You can return values from navigation, just like `.pop`. +To achieve this, pass the type you expect to return as type parameter to `Route`: + +```dart +@override +final List routes = [ + // This router expects to receive a `String` when popped. + ModularRoute('/event', child: (_, __) => EventPage()), +] +``` + +Now, use `.pop` as you use with `Navigator.pop`: + +```dart +// Push route +String name = await Modular.to.pushNamed(); + +// And pass the value when popping +Modular.to.pop('banana'); +``` + +## Flutter Web URL routes (Deeplink-like) + +The routing system can recognize what is in the URL and navigate to a specific part of the application. +Dynamic routes apply here as well. The following URL, for instance, will open the Product view, with `args.params['id']` set to `1`. + +``` +https://flutter-website.com/#/product/1 +``` + +## Creating child modules + +You can create as many modules in your project as you wish, but they will be dependent of the main module. To do so, instead of inheriting from `MainModule`, you should inherit from `ChildModule`: + +```dart +class HomeModule extends ChildModule { + @override + final List binds = [ + Bind.singleton((i) => HomeBloc()), + ]; + + @override + final List routes = [ + ChildRoute('/', child: (_, args) => HomeWidget()), + ChildRoute('/list', child: (_, args) => ListWidget()), + ]; + +} +``` + +You may then pass the submodule to a `Route` in your main module through the `module` parameter: + +```dart +class AppModule extends MainModule { + + @override + final List routes = [ + ModuleRoute('/home', module: HomeModule()), + ]; +} +``` + +We recommend that you split your code in various modules, such as `AuthModule`, and place all the routes related to this module within it. By doing so, it will much easier to maintain and share your code with other projects. + +> **NOTE:** Use the ModuleRoute object to create a Complex Route. + ## Route guard Route guards are middleware-like objects that allow you to control the access of a given route from other route. You can implement a route guard by making a class that `implements RouteGuard`. @@ -260,9 +326,9 @@ To use your `RouteGuard` in a route, pass it to the `guards` parameter: ```dart @override -List routers = [ - final ModularRoute('/', module: HomeModule()), - final ModularRoute( +List routes = [ + final ModuleRoute('/', module: HomeModule()), + final ModuleRoute( '/admin', module: AdminModule(), guards: [MyGuard()], @@ -278,7 +344,7 @@ If placed on a module route, `RouterGuard` will be global to that route. You can choose which type of animation do you want to be used on your pages transition by setting the `Route` `transition` parameter, providing a `TransitionType`. ```dart -ModularRoute('/product', +ModuleRoute('/product', module: AdminModule(), transition: TransitionType.fadeIn, ), //use for change transition @@ -291,7 +357,7 @@ If you use transition in a module, all routes in that module will inherit this t You can also use a custom transition animation by setting the Router parameters `transition` and `customTransition` with `TransitionType.custom` and your `CustomTransition`, respectively: ```dart -ModularRoute('/product', +ModuleRoute('/product', module: AdminModule(), transition: TransitionType.custom, customTransition: myCustomTransition, @@ -335,38 +401,6 @@ CustomTransition get myCustomTransition => CustomTransition( ); ``` -## Route generic types - -You can return values from navigation, just like `.pop`. -To achieve this, pass the type you expect to return as type parameter to `Route`: - -```dart -@override -final List routers => [ - // This router expects to receive a `String` when popped. - ModularRoute('/event', child: (_, __) => EventPage()), -] -``` - -Now, use `.pop` as you use with `Navigator.pop`: - -```dart -// Push route -String name = await Modular.to.pushNamed(); - -// And pass the value when popping -Modular.to.pop('banana'); -``` - -## Flutter Web URL routes (Deeplink-like) - -The routing system can recognize what is in the URL and navigate to a specific part of the application. -Dynamic routes apply here as well. The following URL, for instance, will open the Product view, with `args.params['id']` set to `1`. - -``` -https://flutter-website.com/#/product/1 -``` - ## Dependency Injection You can inject any class into your module by overriding the `binds` getter of your module. Typical examples to inject are BLoCs, ChangeNotifier classes or stores(MobX). @@ -378,7 +412,7 @@ class AppModule extends MainModule { // Provide a list of dependencies to inject into your project @override - List get binds => [ + final List binds = [ Bind((i) => AppBloc()), Bind.factory((i) => AppBloc()), Bind.instance(myObject), @@ -457,40 +491,6 @@ class _MyWidgetState extends ModularState { } ``` -## Creating child modules - -You can create as many modules in your project as you wish, but they will be dependent of the main module. To do so, instead of inheriting from `MainModule`, you should inherit from `ChildModule`: - -```dart -class HomeModule extends ChildModule { - @override - final List binds = [ - Bind.singleton((i) => HomeBloc()), - ]; - - @override - final List routers = [ - ModularRoute('/', child: (_, args) => HomeWidget()), - ModularRoute('/list', child: (_, args) => ListWidget()), - ]; - -} -``` - -You may then pass the submodule to a `Route` in your main module through the `module` parameter: - -```dart -class AppModule extends MainModule { - - @override - final List routers = [ - ModularRoute('/home', module: HomeModule()), - ]; -} -``` - -We recommend that you split your code in various modules, such as `AuthModule`, and place all the routes related to this module within it. By doing so, it will much easier to maintain and share your code with other projects. - ### WidgetModule `WidgetModule` has the same structure as `MainModule`/`ChildModule`. It is very useful if you want to have a TabBar with modular pages. @@ -523,7 +523,7 @@ You can only have one `RouterOutlet` per page and it is only able to browse the final List binds = []; @override - final List routers = [ + final List routes = [ ModularRoute( '/start', child: (context, args) => StartPage(), @@ -581,7 +581,7 @@ For example, you can make a repository interface (`ILocalStorage`) that satisfie ```dart @override -final List binds => [ +final List binds = [ Bind((i) => LocalStorageSharePreferences()), ]; ``` From 3879954688a9c9dd95c040404ccf44da537f5fe8 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 13 Dec 2020 17:46:04 -0300 Subject: [PATCH 63/71] fix doc --- README.md | 918 +----------------- flutter_modular copy.png | Bin 0 -> 38733 bytes flutter_modular/example/pubspec.yaml | 83 ++ .../example/test/pubspec copy.yaml | 83 ++ flutter_modular/lib/flutter_modular.dart | 2 +- flutter_modular/pubspec.yaml | 1 + flutter_modular_annotations/.gitignore | 74 ++ flutter_modular_annotations/.metadata | 10 + flutter_modular_annotations/CHANGELOG.md | 3 + flutter_modular_annotations/LICENSE | 201 ++++ flutter_modular_annotations/README.md | 14 + .../lib/flutter_modular_annotations.dart | 2 + flutter_modular_annotations/pubspec.yaml | 52 + modular.code-workspace | 3 + 14 files changed, 529 insertions(+), 917 deletions(-) create mode 100644 flutter_modular copy.png create mode 100644 flutter_modular/example/pubspec.yaml create mode 100644 flutter_modular/example/test/pubspec copy.yaml create mode 100644 flutter_modular_annotations/.gitignore create mode 100644 flutter_modular_annotations/.metadata create mode 100644 flutter_modular_annotations/CHANGELOG.md create mode 100644 flutter_modular_annotations/LICENSE create mode 100644 flutter_modular_annotations/README.md rename {flutter_modular => flutter_modular_annotations}/lib/flutter_modular_annotations.dart (90%) create mode 100644 flutter_modular_annotations/pubspec.yaml diff --git a/README.md b/README.md index 10182274..d23783d8 100644 --- a/README.md +++ b/README.md @@ -10,926 +10,12 @@ ![flutter_modular](https://raw.githubusercontent.com/Flutterando/modular/master/flutter_modular.png) - -- **[What is Flutter Modular?](#what-is-flutter-modular)** -- **[Modular Structure](#modular-structure)** -- **[Modular Pillars](#modular-pillars)** - - - [Example](#example) - -- **[Getting started with Modular](#getting-started-with-modular)** - - - [Installation](#installation) - - [Using in a New Project](#using-in-a-new-project) - - [Adding Routes](#adding-routes) - - [Dynamic Routes](#dynamic-routes) - - [Route Guard](#route-guard) - - [Route Transition Animation](#route-transition-animation) - - [Grouping Routes](#grouping-routes) - - [Flutter Web url Routes](#flutter-web-url-routes) - - [Dependency Injection](#dependency-injection) - - [Retrieving in view using injection](#retrieving-in-view-using-injection) - -- **[Using Modular widgets to retrieve your classes](#using-modular-widgets-to-retrieve-your-classes)** - - - [ModularState](#modularstate) - - [Consuming a ChangeNotifier Class](#consuming-a-changenotifier-class) - - [Creating Child Modules](#creating-child-modules) - - [WidgetModule](#widgetmodule) - - [RouterOutlet](#routeroutlet) - - [RouterOutletList](#routeroutletlist) - - [Lazy Loading](#lazy-loading) - - [Unit Test](#unit-test) - - [Modular test helper](#modular-test-helper) - - [DebugMode](#debugmode) - -- **[Roadmap](#roadmap)** -- **[Features and bugs](#features-and-bugs)** - -## What is Flutter Modular? - -As an application project grows and becomes complex, it's hard to keep your code and project structure mantainable and reusable. Modular provides a bunch of Flutter-suiting solutions to deal with this problem, like dependency injection, routing system and the "disposable singleton" system (that is, Modular disposes the injected module automatically as it is out of scope). - -Modular's dependency injection system has out-of-the-box support for any state management system, managing your application memory usage. - -## Modular Structure - -Modular structure consists in decoupled and independent modules that will represent the features of the application. -Each module is located in its own directory, and controls its own dependencies, routes, pages, widgets and business logic. -Consequently, you can easily detach one module from your project and use it wherever you want. - -## Modular Pillars - -These are the main aspects that Modular focus on: - -- Automatic Memory Management. -- Dependency Injection. -- Dynamic Routing. -- Code Modularization. - -## Examples - -- [Github Search](https://github.com/Flutterando/github_search) - # Getting started with Modular -## Installation - -Open your project's `pubspec.yaml` and add `flutter_modular` as a dependency: - -```yaml -dependencies: - flutter_modular: any -``` - -You can also provide the git repository as source instead, to try out the newest features and fixes: - -```yaml -dependencies: - flutter_modular: - git: - url: https://github.com/Flutterando/modular -``` - -## Using in a new project - -To use Modular in a new project, you will have to make some initial setup: - -1. Create your main widget with a `MaterialApp` and set its `initialRoute`. On `onGenerateroute`, you will have to provide Modular's routing system (`Modular.generateRoute`), so it can manage your routes. - -```dart -// app_widget.dart -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -class AppWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - // set your initial route - initialRoute: "/", - navigatorKey: Modular.navigatorKey, - // add Modular to manage the routing system - onGenerateRoute: Modular.generateRoute, - ); - } -} -``` - -2. Create your project's main module file extending `MainModule`: - -```dart -// app_module.dart -class AppModule extends MainModule { - - // Provide a list of dependencies to inject into your project - @override - List get binds => []; - - // Provide all the routes for your module - @override - List get routers => []; - - // Provide the root widget associated with your module - // In this case, it's the widget you created in the first step - @override - Widget get bootstrap => AppWidget(); -} -``` - -3. In your `main.dart`, wrap your main module in `ModularApp` to initialize it with Modular: - -```dart -// main.dart -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import 'app/app_module.dart'; - -void main() => runApp(ModularApp(module: AppModule())); -``` - -4. Done! Your app is set and ready to work with Modular! - -## Adding routes - -Your module's routes are provided by overriding the `routers` getter: - -```dart -// app_module.dart -class AppModule extends MainModule { - - // Provide a list of dependencies to inject into your project - @override - List get binds => []; - - // Provide all the routes for your module - @override - List get routers => [ - ModularRouter('/', child: (_, __) => HomePage()), - ModularRouter('/login', child: (_, __) => LoginPage()), - ]; - - // Provide the root widget associated with your module - @override - Widget get bootstrap => AppWidget(); -} -``` - -To push your route to your app, you can use `Navigator.pushNamed`: - -```dart -Navigator.pushNamed(context, '/login'); -``` - -Alternatively, you can use `Modular.to.pushNamed`, in which you don't have to provide a `BuildContext`: - -```dart -Modular.to.pushNamed('/login'); -``` - -### Navigation on the current module - -Use `Modular.to` for literal paths or `Modular.link` for routes in current module: - -```dart -// Modules Home → Product -Modular.to.pushNamed('/home/product/list'); -Modular.to.pushNamed('/home/product/detail/:id'); - -// Inside Product module, use Modular.link and navigate between Product module routes -Modular.link.pushNamed('/list'); -Modular.link.pushNamed('/detail/:id'); - -``` - -## Dynamic routes - -You can use the dynamic routing system to provide parameters to your `Router`: - -```dart -// Use :parameter_name syntax to provide a parameter in your route. -// Route arguments will be available through `args`, and may be accessed in `params` property, -// using square brackets notation (['parameter_name']). - -@override -List get routers => [ - ModularRouter( - '/product/:id', - child: (_, args) => Product(id: args.params['id']), - ), -]; -``` - -The parameter will, then, be pattern-matched when calling the given route. For example: - -```dart -// In this case, `args.params['id']` will have the value `1`. -Modular.to.pushNamed('/product/1'); -``` - -This notation, however, is only valid for simple literals. If you want to pass a complex object to your route, provide it in `arguments` parameter: - -```dart -Modular.to.pushNamed('/product', arguments: ProductModel()); -``` - -And it will be available in the `args.data` property instead of `args.params`: - -```dart -@override -List get routers => [ - ModularRouter( - '/product', - child: (_, args) => Product(model: args.data), - ), -]; -``` - -## Route guard - -Route guards are middleware-like objects that allow you to control the access of a given route from other route. You can implement a route guard by making a class that `implements RouteGuard`. - -For example, the following class will only allow a redirection from `/admin` route: - -```dart -class MyGuard implements RouteGuard { - @override - bool canActivate(String url) { - if (url != '/admin'){ - // Return `true` to allow access - return true; - } else { - // Return `false` to disallow access - return false - } - } -} -``` - -To use your `RouteGuard` in a route, pass it to the `guards` parameter: - -```dart -@override -List get routers => [ - ModularRouter('/', module: HomeModule()), - ModularRouter( - '/admin', - module: AdminModule(), - guards: [MyGuard()], - ), -]; - -``` - -If placed on a module route, `RouterGuard` will be global to that route. - -## Route transition animation - -You can choose which type of animation you want to be used on your pages transition by setting the `Router`'s `transition` parameter, providing a `TransitionType`. - -```dart -ModularRouter('/product', - module: AdminModule(), - transition: TransitionType.fadeIn, -), //use for change transition -``` - -If you use transition in a module, all routes in that module will inherit this transition animation. - -### Custom transition animation route - -You can also use a custom transition animation by setting the Router parameters `transition` and `customTransition` with `TransitionType.custom` and your `CustomTransition`, respectively: - -```dart -ModularRouter('/product', - module: AdminModule(), - transition: TransitionType.custom, - customTransition: myCustomTransition, -), -``` - -For example, this is a custom transition that could be declared in a separated file and used in the `customTransition` parameter: - -```dart -import 'package:flutter/material.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -CustomTransition get myCustomTransition => CustomTransition( - transitionDuration: Duration(milliseconds: 500), - transitionBuilder: (context, animation, secondaryAnimation, child){ - return RotationTransition(turns: animation, - child: SlideTransition( - position: Tween( - begin: const Offset(-1.0, 0.0), - end: Offset.zero, - ).animate(animation), - child: ScaleTransition( - scale: Tween( - begin: 0.0, - end: 1.0, - ).animate(CurvedAnimation( - parent: animation, - curve: Interval( - 0.00, - 0.50, - curve: Curves.linear, - ), - ), - ), - child: child, - ), - ), - ) - ; - }, - ); -``` - -## Grouping routes - -You can group routes that contains one or more common properties. Properties like `guards`, `transition` and `customTransition` can be provided both for single routes and groups of routes: - -```dart -List get routers => [ - ModularRouter('/', module: HomeModule()), - Router.group( - guards: [MyGuard()], - routes: [ - ModularRouter("/admin", module: AdminModule()), - ModularRouter("/profile", module: ProfileModule()), - ], - ), -); -``` - -## Router generic types - -You can return values from navigation, just like `.pop`. -To achieve this, pass the type you expect to return as type parameter to `Router`: - -```dart -@override -List get routers => [ - // This router expects to receive a `String` when popped. - ModularRouter('/event', child: (_, __) => EventPage()), -] -``` - -Now, use `.pop` as you would with `Navigator.pop`: - -```dart -// Push route -String name = await Modular.to.pushNamed(); - -// And pass the value when popping -Modular.to.pop('Jacob Moura'); -``` - -## Flutter Web URL routes (Deeplink-like) - -The routing system can recognize what is in the URL and navigate to a specific part of the application. -Dynamic routes apply here as well. The following URL, for instance, will open the Product view, with `args.params['id']` set to `1`. - -``` -https://flutter-website.com/#/product/1 -``` - -## Dependency Injection - -You can inject any class into your module by overriding the `binds` getter of your module. Typical examples to inject are BLoCs, ChangeNotifier classes or stores. - -A `Bind` object is responsible for configuring the object injection. - -```dart -class AppModule extends MainModule { - - // Provide a list of dependencies to inject into your project - @override - List get binds => [ - Bind((_) => AppBloc()), // Injecting a BLoC - Bind((_) => Counter()), // Injecting a ChangeNotifier class - ]; - - // Provide all the routes for your module - @override - List get routers => [ - ModularRouter('/', child: (_, args) => HomePage()), - ModularRouter('/login', child: (_, args) => LoginPage()), - ]; - - // Provide the root widget associated with your module - @override - Widget get bootstrap => AppWidget(); -} -``` - -### Retrieving your injected dependencies in the view - -Let's assume the following BLoC has been defined and injected in our module (as in the previous example): - -```dart -import 'package:flutter_modular/flutter_modular.dart' show Disposable; - -// In Modular, `Disposable` classes are automatically disposed when out of the module scope. - -class AppBloc extends Disposable { - final controller = StreamController(); - - @override - void dispose() { - controller.close(); - } -} -``` - -There are several ways to retrieve our injected `AppBloc`. - -```dart -class HomePage extends StatelessWidget { - - @override - Widget build(BuildContext context) { - - // You can use the object Inject to retrieve.. - - final appBloc = Modular.get(); - //... - } -} -``` - -By default, objects in Bind are singletons and lazy. -When Bind is lazy, the object will only be instantiated when it is called for the first time. You can use 'lazy: false' if you want your object to be instantiated immediately (eager-loaded). - -```dart -Bind((i) => OtherWidgetNotLazy(), lazy: false), -``` - -If you want the injected object to be instantiated every time it is called (instead of being a singleton instance), you may simple pass `false` to the `singleton` parameter: - -```dart -Bind((i) => OtherWidgetNotLazy(), singleton: false), -``` - -## Using Modular widgets to retrieve your classes - -### ModularState - -```dart -class MyWidget extends StatefulWidget { - @override - _MyWidgetState createState() => _MyWidgetState(); -} - -class _MyWidgetState extends ModularState { - - // Variable controller - // Automatic dispose of HomeController - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text("Modular"), - ), - body: Center(child: Text("${controller.counter}"),), - ); - } -} -``` - -## Consuming a ChangeNotifier class - -Example of a `ChangeNotifier` class: - -```dart -import 'package:flutter/material.dart'; - -class Counter extends ChangeNotifier { - int counter = 0; - - increment() { - counter++; - notifyListeners(); - } -} -``` - -you can use the `Consumer` to manage the state of a widget block. - -```dart -class HomePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - - return Scaffold( - appBar: AppBar(title: Text("Home")), - body: Center( - // By passing your ChangeNotifier class as type parameter, the `builder` will be called every time `notifyListeners` is called - child: Consumer( - builder: (context, value) { - return Text('Counter ${value.counter}'); - } - ), - ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.add), - onPressed: () { - // You can retrive the class directly with `get` and execute the increment method - get().increment(); - }, - ), - ); - } -} -``` - -## Creating child modules - -You can create as many modules in your project as you wish, but they will be dependent of the main module. To do so, instead of inheriting from `MainModule`, you should inherit from `ChildModule`: - -```dart -class HomeModule extends ChildModule { - @override - List get binds => [ - Bind((i) => HomeBloc()), - ]; - - @override - List get routers => [ - ModularRouter('/', child: (_, args) => HomeWidget()), - ModularRouter('/list', child: (_, args) => ListWidget()), - ]; - - static Inject get to => Inject.of(); -} -``` - -You may then pass the submodule to a `Router` in your main module through the `module` parameter: - -```dart -class AppModule extends MainModule { - - @override - List get routers => [ - ModularRouter('/home', module: HomeModule()), - ]; -} -``` - -We recommend that you split your code in various modules, such as `LoginModule`, and place all the routes related to this module within it. By doing so, it will much easier to maintain and share your code with other projects. - -### WidgetModule - -`WidgetModule` has the same structure as `MainModule`/`ChildModule`. It is very useful if you want to have a TabBar with modular pages. - -```dart -class TabModule extends WidgetModule { - - @override - List get binds => [ - Bind((i) => TabBloc(repository: i())), - Bind((i) => TabRepository()), - ]; - - Widget get view => TabPage(); - -} - -``` - -## RouterOutlet - -A `RouterOutlet` may be used if you need a routing system that is totally detached from the main routing system. This is useful, for example, when you need an element to have its own set of routes, even though it is inside a page on the main route. - -A practical example of this is its use in a `TabBar` or `Drawer`: - -```dart -PageView( - controller: controller - children: [ - RouterOutlet( - module: Tab1Module() - ), - RouterOutlet( - module: Tab2Module() - ), - RouterOutlet( - module: Tab3Module() - ), - ] -), -``` - -> **NOTE:** Navigation within these modules are only supported through `Navigator.of(context)` or `Modular.navigator` using literal routes paths. - -## RouterOutletList - -Using multiples RouterOutlets. - -```dart - var controller = RouterOutletListController(); - controller.listen((value) { - setState(() { - currentIndex = value; - }); - }); -.... - RouterOutletList( - modules: [ - Tab1Module(), - Tab2Module(), - ], controller: controller, - ), -``` - - - -## Lazy loading - -Another benefit you get when working with modules is that they are (by default) lazily-loaded. This means that your dependency injection will only be available when you navigate to a module, and when you exit that module, Modular will manage the resources disposal by removing all injections and executing `dispose()` (if available) on each injected dependency. - -## Unit test - -You can use the dependency injection system to replace a `Bind` with a mocked `Bind`, like, for example, a mocked repository. You can also do it using "Inversion of Control" (IoC). - -For example, you can make a repository interface (`ILocalStorage`) that satisfies your repository contract requirement and pass it as a paramter type to `Bind`. - -```dart -@override -List get binds => [ - Bind((i) => LocalStorageSharePreferences()), -]; -``` - -Then, on your test file, you import `flutter_modular_test` and provide your mocked repository in the `initModule` as a replacement of your concrete repository: - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - test('change bind', () { - initModule(AppModule(), changeBinds: [ - Bind((i) => LocalMock()), - ]); - expect(Modular.get(), isA()); - }); -} -``` -## Modular test helper - -Before write in your test file, if you want to improve readability you might to import `flutter_modular_test` and define your mocked module using `IModularTest` and override his methods to create a mock, similar as `ChildModule`, when writing your tests: - -The first step is write a class like that: - -```dart - -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; - -class InitAppModuleHelper extends IModularTest { - - final ModularTestType modularTestType; - IModularTest({this.modularTestType: ModularTestType.resetModule}); - - @override - List get binds => [ - Bind((i) => LocalStorageSharePreference()), - ]; - - @override - ChildModule get module => AppModule(); - - - @override - IModularTest get modulardependency => null; - -} - -``` - -The right way to use is writing as least one of that per module, its important to remember to put the modular dependecies in `modularDependency`. its useful because when you load this module for testing, all related modules will be load together. In this case the `AppModule` is the root module and it hasn`t dependency. - -### Load Modular helper on tests - -1. By default when use `IModularTest` each `InitAppModuleHelper().load()` will clean and rebuid the modular and his injects, this is fine to do -each test block independent and make more easy to write modular tests without noise. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - test('change bind', () { - InitAppModuleHelper().load(); - //do something - }); - test('change bind', () { - InitAppModuleHelper().load(); - //do something - }); -} -``` - -2. To keep previous modular and its injects you can pass the param `modularTestType`. -> **NOTE:** With `modularTestType.keepModulesOnMemory`, it won't clean the modules that already have been loaded. (It doesn't call `Modular.removeModule()`) - - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - - test('test1', () { - InitAppModuleHelper().load(); - }); - - test('test2', () { - InitAppModuleHelper( - modularTestType: ModularTestType.keepModulesOnMemory - ).load(); - // Keep the same injects loaded by test1 - }); -} -``` - -3. Changing the binds when `load()` the module like `initModule()`. - -> **NOTE:** It also can change binds of another modules that are its dependencies until find the MainModule. - -Ex: When you have a tree like `InitAppModuleHelper` <- `InitHomeModuleHelper`, when you call `InitHomeModuleHelper.load(changeBinds:[])` it will be able to change binds on `HomeModule` and `AppModule`. Because of that you only need one changeBinds array and it can make all the changes for you, see it on section: [Create helper for a child module](#create-helper-for-a-child-module). - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - - test('test1', () { - InitAppModuleHelper().load(changeBinds:[ - Bind((i) => LocalStorageHive()) - - ]); - }); - -} -``` -### Create helper for a child module -Remember you only need to call the most deeper `IModularTest` and it can load all dependency modules you have added on your mock definition, like the next example: - -The first step is define a `IModularTest` to another module, pay attention that the `HomeModule` is a child of `AppModule`, because of that you need to put the `AppModule` on `modularDependency`. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; -import 'package:flutter_modular/src/inject/bind.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import '../../app_module_test_modular.dart'; -import 'home_module.dart'; - -class InitHomeModuleHelper extends IModularTest { - - @override - List get binds => []; - - @override - ChildModule get module => HomeModule(); - - @override - IModularTest get modulardependency => InitAppModuleHelper(); - -} -``` - -Now we can init the `HomeModule` and all his dependencies just by typing `InitHomeModuleHelper().load()` on your `test_file`. It doesn't matter how deep is your module, all dependencies are recursively loaded in a batch, you only need to create a `IModuleTest` for each one and put your dependencies correctly and it will work fine. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'app/modules/home/home_module_test_modular.dart'; -main() { - test('change bind', () { - InitHomeModuleHelper().load(); - //do something - }); - test('change bind', () { - InitHomeModuleHelper().load(); - //do something - }); -} -``` - -### Mocking with mockito - -1. Add the mock into the `binds` list on your `IModularTest` helper, if you dont need to change during the tests. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; -import 'package:flutter_modular/src/inject/bind.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:mockito/mockito.dart'; - -import '../../app_module_test_modular.dart'; -import 'home_module.dart'; - -class LocalStorageMock extends Mock implements ILocalStorage {} - -class InitHomeModuleHelper extends IModularTest { - - @override - List get binds => [ - Bind((i) => LocalStorageMock()), - ]; - - @override - ChildModule get module => HomeModule(); - - @override - IModularTest get modulardependency => InitAppModuleHelper(); - -} - - -``` - -2. Get the instance using `Modular.get()` and change the behavior as you need in the middle of the test: - -```dart -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -import 'app/modules/home/home_module_test_modular.dart'; - -class LocalStorageMock extends Mock implements ILocalStorage {} - -main() { - - LocalStorageMock localStorageMock = LocalStorageMock(); - - group("IModuleTest", () { - setUp(() { - InitAppModuleHelper().load(changeBinds:[ - - Bind((i) => localStorageMock), - - ]); - ILocalStorage iLocalStorage = Modular.get(); - }); - - test('change bind', () { - when(localStorageMock.doSomething()).thenReturn("Hello"); - iLocalStorage.doSomething(); - //return Hello - - when(localStorageMock.doSomething()).thenReturn("World"); - iLocalStorage.doSomething(); - //return World - }); - - }); - -} -``` -### Mock the navigation system - -We though it would be interesting to provide a native way to mock the navigation system when used with `Modular.to` and `Modular.link`. To do this, you may just implement `IModularNavigator` and pass your implementation to `Modular.navigatorDelegate`. - -```dart -// Modular.to and Modular.link will be called MyNavigatorMock implements! -Modular.navigatorDelegate = MyNavigatorMock(); -``` - -## DebugMode - -By default, Modular prints a lot of debug info in the console. You may disable this by disabling `debugMode`: - -```dart -Modular.debugMode = false; -``` - -## Roadmap +- [flutter_modular Documentation](https://github.com/Flutterando/modular/tree/master/flutter_modular) -This is our current roadmap. Please, feel free to request additions/changes. +- [modular_codegen Documentation](https://github.com/Flutterando/modular/tree/master/modular_codegen) -| Feature | Progress | -| :-------------------------------- | :------: | -| DI by Module | ✅ | -| Routes by Module | ✅ | -| Widget Consume for ChangeNotifier | ✅ | -| Auto-dispose | ✅ | -| Integration with flutter_bloc | ✅ | -| Integration with mobx | ✅ | -| Multiple routes | ✅ | -| Pass arguments by route | ✅ | -| Pass url parameters per route | ✅ | -| Route Transition Animation | ✅ | ## Features and bugs diff --git a/flutter_modular copy.png b/flutter_modular copy.png new file mode 100644 index 0000000000000000000000000000000000000000..7a77c9a50022c255a2d8b63a462f6a9ae8790ab6 GIT binary patch literal 38733 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 U6Y-?X615(2Vd>`u&vf4YFA-dQ=>Px# literal 0 HcmV?d00001 diff --git a/flutter_modular/example/pubspec.yaml b/flutter_modular/example/pubspec.yaml new file mode 100644 index 00000000..62ff0464 --- /dev/null +++ b/flutter_modular/example/pubspec.yaml @@ -0,0 +1,83 @@ +name: infinity_list +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.12.0-0 <3.0.0" + +dependencies: + flutter_modular: + path: ../../flutter_modular + http: + git: https://github.com/dart-lang/http + + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.1 + +dev_dependencies: + mockito: + git: + url: https://github.com/felangel/mockito.git + ref: deps/update-to-null-safety + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_modular/example/test/pubspec copy.yaml b/flutter_modular/example/test/pubspec copy.yaml new file mode 100644 index 00000000..05fc0bd8 --- /dev/null +++ b/flutter_modular/example/test/pubspec copy.yaml @@ -0,0 +1,83 @@ +name: infinity_list +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.12.0-0 <3.0.0" + +dependencies: + flutter_modular: + path: /Users/jacobmoura/Projects/modular/flutter_modular + http: + git: https://github.com/dart-lang/http + + flutter: + sdk: flutter + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.1 + +dev_dependencies: + mockito: + git: + url: https://github.com/felangel/mockito.git + ref: deps/update-to-null-safety + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 13f405f5..34745668 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -1,6 +1,6 @@ library flutter_modular; -export 'flutter_modular_annotations.dart'; +export 'package:flutter_modular_annotations/flutter_modular_annotations.dart'; export 'src/core/inject/bind.dart'; export 'src/core/inject/inject.dart'; export 'src/core/interfaces/disposable.dart'; diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index c9160659..38b1ee2b 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -7,6 +7,7 @@ environment: sdk: ">=2.12.0-0 <3.0.0" dependencies: + flutter_modular_annotations: ^0.0.2 flutter: sdk: flutter diff --git a/flutter_modular_annotations/.gitignore b/flutter_modular_annotations/.gitignore new file mode 100644 index 00000000..1985397a --- /dev/null +++ b/flutter_modular_annotations/.gitignore @@ -0,0 +1,74 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/flutter_modular_annotations/.metadata b/flutter_modular_annotations/.metadata new file mode 100644 index 00000000..81b4ae45 --- /dev/null +++ b/flutter_modular_annotations/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: a76bb1a08e3d22ea73a5f8005e6e46925ee938c3 + channel: master + +project_type: package diff --git a/flutter_modular_annotations/CHANGELOG.md b/flutter_modular_annotations/CHANGELOG.md new file mode 100644 index 00000000..ac071598 --- /dev/null +++ b/flutter_modular_annotations/CHANGELOG.md @@ -0,0 +1,3 @@ +## [0.0.1] - TODO: Add release date. + +* TODO: Describe initial release. diff --git a/flutter_modular_annotations/LICENSE b/flutter_modular_annotations/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/flutter_modular_annotations/LICENSE @@ -0,0 +1,201 @@ + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/flutter_modular_annotations/README.md b/flutter_modular_annotations/README.md new file mode 100644 index 00000000..6787a05d --- /dev/null +++ b/flutter_modular_annotations/README.md @@ -0,0 +1,14 @@ +# flutter_modular_annotations + +A new Flutter package project. + +## Getting Started + +This project is a starting point for a Dart +[package](https://flutter.dev/developing-packages/), +a library module containing code that can be shared easily across +multiple Flutter or Dart projects. + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/flutter_modular/lib/flutter_modular_annotations.dart b/flutter_modular_annotations/lib/flutter_modular_annotations.dart similarity index 90% rename from flutter_modular/lib/flutter_modular_annotations.dart rename to flutter_modular_annotations/lib/flutter_modular_annotations.dart index 8672a8b8..dad14c4a 100644 --- a/flutter_modular/lib/flutter_modular_annotations.dart +++ b/flutter_modular_annotations/lib/flutter_modular_annotations.dart @@ -1,3 +1,5 @@ +library flutter_modular_annotations; + class Injectable { final bool singleton; final bool lazy; diff --git a/flutter_modular_annotations/pubspec.yaml b/flutter_modular_annotations/pubspec.yaml new file mode 100644 index 00000000..8983a17f --- /dev/null +++ b/flutter_modular_annotations/pubspec.yaml @@ -0,0 +1,52 @@ +name: flutter_modular_annotations +description: Smart project structure with dependency injection and route management +version: 0.0.2 +homepage: https://github.com/Flutterando/modular + +environment: + sdk: ">=2.12.0-0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/modular.code-workspace b/modular.code-workspace index 2aaee144..2fb58ed4 100644 --- a/modular.code-workspace +++ b/modular.code-workspace @@ -5,6 +5,9 @@ }, { "path": "modular_codegen" + }, + { + "path": "flutter_modular_annotations" } ], "settings": { From 6a6da2bb25555161f3a9d4461b34cbe001938a32 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Sun, 13 Dec 2020 18:06:59 -0300 Subject: [PATCH 64/71] annotation package --- .../lib/src/custom_annotation_generator.dart | 2 +- .../lib/src/injection_generator.dart | 10 +++++----- modular_codegen/pubspec.yaml | 18 +++++++----------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/modular_codegen/lib/src/custom_annotation_generator.dart b/modular_codegen/lib/src/custom_annotation_generator.dart index e108bd87..005e0092 100644 --- a/modular_codegen/lib/src/custom_annotation_generator.dart +++ b/modular_codegen/lib/src/custom_annotation_generator.dart @@ -7,7 +7,7 @@ abstract class CustomGeneratorForAnnotatedField extends Generator { /// Returns the annotation of type [AnnotationType] of the given [element], /// or [null] if it doesn't have any. - DartObject getAnnotation(Element element) { + DartObject? getAnnotation(Element element) { final annotations = TypeChecker.fromRuntime(AnnotationType).annotationsOf(element); if (annotations.isEmpty) { diff --git a/modular_codegen/lib/src/injection_generator.dart b/modular_codegen/lib/src/injection_generator.dart index 03183826..e274f8e1 100644 --- a/modular_codegen/lib/src/injection_generator.dart +++ b/modular_codegen/lib/src/injection_generator.dart @@ -3,7 +3,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/dart/element/visitor.dart'; import 'package:build/build.dart'; -import 'package:flutter_modular/flutter_modular_annotations.dart'; +import 'package:flutter_modular_annotations/flutter_modular_annotations.dart'; import 'package:source_gen/source_gen.dart'; class InjectionGenerator extends GeneratorForAnnotation { @@ -37,7 +37,7 @@ class InjectionGenerator extends GeneratorForAnnotation { } class ModelVisitor extends SimpleElementVisitor { - DartType className; + DartType? className; List params = []; bool isAnnotation = false; @@ -52,11 +52,11 @@ class ModelVisitor extends SimpleElementVisitor { return param.element.displayName == "Data" || param.element.displayName == "Param" || param.element.displayName == "Default"; - }, orElse: () => null) != + }, orElse: (() => null!) as ElementAnnotation Function()?) != null; } return false; - }, orElse: () => null) != + }, orElse: (() => null!) as ParameterElement Function()?) != null; writeParams(element.parameters); } @@ -64,7 +64,7 @@ class ModelVisitor extends SimpleElementVisitor { writeParams(List parameters) { params = parameters.map((param) { if (param.metadata.length > 0) { - String arg; + String? arg; for (var meta in param.metadata) { if (meta.element.displayName == 'Param') { diff --git a/modular_codegen/pubspec.yaml b/modular_codegen/pubspec.yaml index b87bb4a9..ab0e3379 100644 --- a/modular_codegen/pubspec.yaml +++ b/modular_codegen/pubspec.yaml @@ -1,27 +1,23 @@ name: modular_codegen description: Code Generate for flutter_modular. Inject Automation. Annotation @Inject, @Param and @Data. -version: 2.0.1 +version: 3.0.0-nullsafety.1 homepage: https://github.com/Flutterando/modular environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" dependencies: - flutter_modular: ">=2.0.0 <3.0.0" - analyzer: ">=0.38.5 <0.41.0" - glob: ^1.2.0 + flutter_modular_annotations: ^0.0.2 + analyzer: ">=0.38.5 <0.42.0" + glob: ^2.0.0-nullsafety.0 build: '>=0.12.0 <2.0.0' - build_resolvers: ^1.3.11 - source_gen: ^0.9.6 + build_resolvers: ^1.4.4 + source_gen: ^0.9.10 meta: ">=1.1.8 <2.0.0" flutter: sdk: flutter dev_dependencies: - build_config: ^0.4.2 - build_runner: ">=1.10.0 <2.0.0" - build_test: ^1.2.0 - test: ^1.15.3 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec From 287651dceae7efc00306b05efa227c4c74c52597 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Mon, 14 Dec 2020 18:26:55 -0300 Subject: [PATCH 65/71] change version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 38b1ee2b..008557e3 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.13 +version: 3.0.0-nullsafety.14 homepage: https://github.com/Flutterando/modular environment: From 94f7c9323559214c4d78e54b82445ab6ffab3694 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 15 Dec 2020 01:22:01 -0300 Subject: [PATCH 66/71] change name of wildcard route --- flutter_modular/README.md | 2 +- flutter_modular/lib/flutter_modular.dart | 2 +- .../src/core/models/{wildcard.dart => wildcard_route.dart} | 4 ++-- flutter_modular/pubspec.yaml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename flutter_modular/lib/src/core/models/{wildcard.dart => wildcard_route.dart} (92%) diff --git a/flutter_modular/README.md b/flutter_modular/README.md index 75281f9a..8a6d7640 100644 --- a/flutter_modular/README.md +++ b/flutter_modular/README.md @@ -182,7 +182,7 @@ You can use Relative Navigation to navigate like web ```dart // Modules Home → Product Modular.to.navigate('/home/product/list'); -Modular.to.navigate('/home/product/detail/:id'); +Modular.to.navigate('/home/product/detail/3'); // Relative Navigation inside /home/product/list Modular.to.navigate('detail/3'); // it's the same as /home/product/detail/3 diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 34745668..48f4ce57 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -10,7 +10,7 @@ export 'src/core/models/child_route.dart'; export 'src/core/models/custom_transition.dart'; export 'src/core/models/modular_arguments.dart'; export 'src/core/models/module_route.dart'; -export 'src/core/models/wildcard.dart'; +export 'src/core/models/wildcard_route.dart'; export 'src/core/modules/child_module.dart'; export 'src/core/modules/main_module.dart'; export 'src/presenters/modular_base.dart'; diff --git a/flutter_modular/lib/src/core/models/wildcard.dart b/flutter_modular/lib/src/core/models/wildcard_route.dart similarity index 92% rename from flutter_modular/lib/src/core/models/wildcard.dart rename to flutter_modular/lib/src/core/models/wildcard_route.dart index 3c4bdb27..6de667b1 100644 --- a/flutter_modular/lib/src/core/models/wildcard.dart +++ b/flutter_modular/lib/src/core/models/wildcard_route.dart @@ -6,8 +6,8 @@ import 'custom_transition.dart'; import 'modular_arguments.dart'; import 'modular_route_impl.dart'; -class WildCard extends ModularRouteImpl { - WildCard({ +class WildcardRoute extends ModularRouteImpl { + WildcardRoute({ List children = const [], required Widget Function(BuildContext, ModularArguments?) child, List? guards, diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 008557e3..d74afac3 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.14 +version: 3.0.0-nullsafety.15 homepage: https://github.com/Flutterando/modular environment: From ea25e26dcf9c7d5278e5713e0d7ffd6cb775d51c Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 15 Dec 2020 19:12:42 -0300 Subject: [PATCH 67/71] fix guards --- .../lib/src/core/models/child_route.dart | 1 + .../lib/src/core/models/module_route.dart | 1 + .../lib/src/core/models/wildcard_route.dart | 1 + .../modular_route_information_parser.dart | 43 +++++++++++-------- .../navigation/modular_router_delegate.dart | 22 +++++++--- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/flutter_modular/lib/src/core/models/child_route.dart b/flutter_modular/lib/src/core/models/child_route.dart index 02b57c72..a952ea62 100644 --- a/flutter_modular/lib/src/core/models/child_route.dart +++ b/flutter_modular/lib/src/core/models/child_route.dart @@ -16,6 +16,7 @@ class ChildRoute extends ModularRouteImpl { CustomTransition? customTransition, Duration duration = const Duration(milliseconds: 300), }) : super(routerName, + routerOutlet: [], duration: duration, child: child, customTransition: customTransition, diff --git a/flutter_modular/lib/src/core/models/module_route.dart b/flutter_modular/lib/src/core/models/module_route.dart index 410e46cc..e03f464a 100644 --- a/flutter_modular/lib/src/core/models/module_route.dart +++ b/flutter_modular/lib/src/core/models/module_route.dart @@ -13,6 +13,7 @@ class ModuleRoute extends ModularRouteImpl { CustomTransition? customTransition, Duration duration = const Duration(milliseconds: 300), }) : super(routerName, + routerOutlet: [], duration: duration, module: module, customTransition: customTransition, diff --git a/flutter_modular/lib/src/core/models/wildcard_route.dart b/flutter_modular/lib/src/core/models/wildcard_route.dart index 6de667b1..7fbfc5ba 100644 --- a/flutter_modular/lib/src/core/models/wildcard_route.dart +++ b/flutter_modular/lib/src/core/models/wildcard_route.dart @@ -15,6 +15,7 @@ class WildcardRoute extends ModularRouteImpl { CustomTransition? customTransition, Duration duration = const Duration(milliseconds: 300), }) : super('**', + routerOutlet: [], duration: duration, child: child, customTransition: customTransition, diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 566ca699..7dd11fa4 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/core/interfaces/route_guard.dart'; import '../../core/errors/errors.dart'; import '../../core/interfaces/modular_route.dart'; @@ -95,12 +96,11 @@ class ModularRouteInformationParser var r = _searchRoute(routeChild, tempRouteName, path); if (r != null) { r.currentModule?.paths.remove(path); - route = route.copyWith(routerOutlet: [ - r.copyWith( - modulePath: r.modulePath == route.modulePath - ? tempRouteName - : r.modulePath), - ], path: tempRouteName); + r = r.copyWith( + modulePath: r.modulePath == route.modulePath + ? tempRouteName + : r.modulePath); + route = route.copyWith(routerOutlet: [r], path: tempRouteName); return route; } } @@ -231,19 +231,28 @@ class ModularRouteInformationParser Future canActivate(String path, ModularRoute router) async { if (router.guards?.isNotEmpty == true) { - for (var guard in router.guards!) { - try { - final result = await guard.canActivate(path, router); - if (!result) { - throw ModularError('$path is NOT ACTIVATE'); - } - // ignore: avoid_catches_without_on_clauses - } catch (e) { - throw ModularError( - 'RouteGuard error. Check ($path) in ${router.currentModule.runtimeType}'); - } + await _checkGuard(path, router); + } else if (router.routerOutlet.isNotEmpty) { + for (final r in router.routerOutlet) { + await _checkGuard(path, r); } } + return router; } + + Future _checkGuard(String path, ModularRoute router) async { + for (var guard in router.guards ?? []) { + try { + final result = await guard.canActivate(path, router); + if (!result) { + throw ModularError('$path is NOT ACTIVATE'); + } + // ignore: avoid_catches_without_on_clauses + } catch (e) { + throw ModularError( + 'RouteGuard error. Check ($path) in ${router.currentModule.runtimeType}'); + } + } + } } diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index 3d4f0d65..7817c6d3 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_modular/src/core/errors/errors.dart'; import '../../core/interfaces/modular_route.dart'; import '../../core/modules/child_module.dart'; @@ -202,7 +203,7 @@ class ModularRouterDelegate extends RouterDelegate final outletRouter = router.routerOutlet.last.copyWith( args: router.args?.copyWith(data: arguments), ); - final page = ModularPage( + var page = ModularPage( key: UniqueKey(), router: outletRouter, ); @@ -215,12 +216,21 @@ class ModularRouterDelegate extends RouterDelegate lastPage.completePop(result); return result; } else { - final lastPage = routerOutlatPages[router.path!]?.last; - routerOutlatPages[router.path!]?.last = page; - currentConfiguration?.routerOutlet.last = outletRouter; - notifyListeners(); + final routeOutletConf = currentConfiguration?.routerOutlet ?? []; + ModularPage? lastPage; + if (routeOutletConf.isEmpty) { + throw ModularError('Prefer Modular.to.navigate()'); + } else { + lastPage = routerOutlatPages[router.path!]?.last; + routerOutlatPages[router.path!]?.last = page; + currentConfiguration?.routerOutlet.last = outletRouter; + notifyListeners(); + } + final result = await page.waitPop(); - lastPage!.completePop(result); + if (lastPage != null) { + lastPage.completePop(result); + } notifyListeners(); return result; } From 22eeb070ac55b74582ea6a9a81e5c49d2ca214ac Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 15 Dec 2020 19:13:08 -0300 Subject: [PATCH 68/71] change version --- flutter_modular/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index d74afac3..e74e5824 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.15 +version: 3.0.0-nullsafety.16 homepage: https://github.com/Flutterando/modular environment: From b9559a1ed3ab7d31f7ef8fa729060a88bbbd9fee Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 15 Dec 2020 23:01:28 -0300 Subject: [PATCH 69/71] added error text --- flutter_modular/lib/src/core/models/module_route.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flutter_modular/lib/src/core/models/module_route.dart b/flutter_modular/lib/src/core/models/module_route.dart index e03f464a..77133e1d 100644 --- a/flutter_modular/lib/src/core/models/module_route.dart +++ b/flutter_modular/lib/src/core/models/module_route.dart @@ -12,7 +12,9 @@ class ModuleRoute extends ModularRouteImpl { TransitionType transition = TransitionType.defaultTransition, CustomTransition? customTransition, Duration duration = const Duration(milliseconds: 300), - }) : super(routerName, + }) : assert(!routerName.contains('/:'), + 'ModuleRoute should not contain dynamic route'), + super(routerName, routerOutlet: [], duration: duration, module: module, From e20a03e4f931c919a7e1eb06c52073585f0b15a6 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 15 Dec 2020 23:46:31 -0300 Subject: [PATCH 70/71] fix extend Object --- flutter_modular/lib/src/core/inject/inject.dart | 4 ++-- .../lib/src/presenters/interfaces/modular_interface.dart | 2 +- flutter_modular/lib/src/presenters/modular_impl.dart | 2 +- flutter_modular/lib/src/presenters/widgets/modular_state.dart | 2 +- flutter_modular/pubspec.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flutter_modular/lib/src/core/inject/inject.dart b/flutter_modular/lib/src/core/inject/inject.dart index 2b3ba01c..b28b68d7 100644 --- a/flutter_modular/lib/src/core/inject/inject.dart +++ b/flutter_modular/lib/src/core/inject/inject.dart @@ -11,10 +11,10 @@ class Inject { Inject({this.params, this.typesInRequest = const []}); - B? call({Map? params, B? defaultValue}) => + B? call({Map? params, B? defaultValue}) => get(params: params, defaultValue: defaultValue); - B? get({Map? params, B? defaultValue}) { + B? get({Map? params, B? defaultValue}) { params ??= {}; return Modular.get( params: params, diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart index bced449c..09a87870 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart @@ -12,7 +12,7 @@ abstract class ModularInterface { void debugPrintModular(String text); IModularNavigator get to; - B? get({ + B? get({ Map params = const {}, List? typesInRequestList, B? defaultValue, diff --git a/flutter_modular/lib/src/presenters/modular_impl.dart b/flutter_modular/lib/src/presenters/modular_impl.dart index c84ac97e..fa551fa2 100644 --- a/flutter_modular/lib/src/presenters/modular_impl.dart +++ b/flutter_modular/lib/src/presenters/modular_impl.dart @@ -63,7 +63,7 @@ class ModularImpl implements ModularInterface { String get initialRoute => '/'; @override - B get( + B get( {Map params = const {}, List? typesInRequestList, B? defaultValue}) { diff --git a/flutter_modular/lib/src/presenters/widgets/modular_state.dart b/flutter_modular/lib/src/presenters/widgets/modular_state.dart index 1984cd47..41ebb2d6 100644 --- a/flutter_modular/lib/src/presenters/widgets/modular_state.dart +++ b/flutter_modular/lib/src/presenters/widgets/modular_state.dart @@ -2,7 +2,7 @@ import 'package:flutter/widgets.dart'; import '../modular_base.dart'; -abstract class ModularState +abstract class ModularState extends State { final TBind? controller = Modular.get(); diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index e74e5824..5524b7b5 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.16 +version: 3.0.0-nullsafety.17 homepage: https://github.com/Flutterando/modular environment: From 26fdb171f4152dda7b568e333d7384f311dcbcbb Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Wed, 16 Dec 2020 16:26:14 -0300 Subject: [PATCH 71/71] normalized --- README.md | 2 + flutter_modular copy.png | Bin 38733 -> 0 bytes flutter_modular.png | Bin 25445 -> 38733 bytes flutter_modular/README.md | 252 ------------------ flutter_modular/lib/flutter_modular.dart | 9 +- flutter_modular/lib/flutter_modular_test.dart | 2 - flutter_modular/lib/src/core/inject/bind.dart | 58 ---- .../{modules => interfaces}/child_module.dart | 23 +- .../interfaces/modular_interface.dart | 4 +- .../modular_navigator_interface.dart | 0 .../src/core/interfaces/modular_route.dart | 9 +- flutter_modular/lib/src/core/models/bind.dart | 55 ++++ .../lib/src/core/models/child_route.dart | 2 +- .../lib/src/core/models/module_route.dart | 6 +- .../lib/src/core/models/wildcard_route.dart | 2 +- .../{core/inject => presenters}/inject.dart | 5 +- .../modules => presenters}/main_module.dart | 2 +- .../lib/src/presenters/modular_base.dart | 4 +- .../lib/src/presenters/modular_impl.dart | 30 +-- .../modular_route_impl.dart | 17 +- .../modular_route_information_parser.dart | 2 +- .../navigation/modular_router_delegate.dart | 4 +- .../transitions/page_transition.dart | 0 .../transitions/transitions.dart | 2 +- .../src/presenters/widgets/modular_app.dart | 2 +- .../src/presenters/widgets/widget_module.dart | 13 +- .../lib/src/test/modular_test_interface.dart | 98 ------- flutter_modular/lib/src/test/utils_test.dart | 45 ---- flutter_modular/pubspec.yaml | 2 +- flutter_modular/rocket.drawio | 13 - .../test/src/core/inject/bind_test.dart | 5 +- .../test/src/core/models/bind_test.dart | 18 ++ .../src/core/models/modular_router_test.dart | 2 +- .../src/core/modules/child_module_test.dart | 54 ++-- .../modular_route_information_parse_test.dart | 41 +-- flutter_modular_test/.gitignore | 74 +++++ flutter_modular_test/.metadata | 10 + flutter_modular_test/CHANGELOG.md | 3 + flutter_modular_test/LICENSE | 201 ++++++++++++++ flutter_modular_test/README.md | 59 ++++ .../lib/flutter_modular_test.dart | 39 +++ flutter_modular_test/pubspec.yaml | 57 ++++ .../test/flutter_modular_test_test.dart | 20 ++ modular.code-workspace | 3 + .../lib/src/custom_annotation_generator.dart | 14 +- .../lib/src/injection_generator.dart | 18 +- modular_codegen/pubspec.yaml | 16 +- 47 files changed, 661 insertions(+), 636 deletions(-) delete mode 100644 flutter_modular copy.png delete mode 100644 flutter_modular/lib/flutter_modular_test.dart delete mode 100644 flutter_modular/lib/src/core/inject/bind.dart rename flutter_modular/lib/src/core/{modules => interfaces}/child_module.dart (81%) rename flutter_modular/lib/src/{presenters => core}/interfaces/modular_interface.dart (83%) rename flutter_modular/lib/src/{presenters => core}/interfaces/modular_navigator_interface.dart (100%) create mode 100644 flutter_modular/lib/src/core/models/bind.dart rename flutter_modular/lib/src/{core/inject => presenters}/inject.dart (90%) rename flutter_modular/lib/src/{core/modules => presenters}/main_module.dart (72%) rename flutter_modular/lib/src/{core/models => presenters}/modular_route_impl.dart (94%) rename flutter_modular/lib/src/{core => presenters}/transitions/page_transition.dart (100%) rename flutter_modular/lib/src/{core => presenters}/transitions/transitions.dart (98%) delete mode 100644 flutter_modular/lib/src/test/modular_test_interface.dart delete mode 100644 flutter_modular/lib/src/test/utils_test.dart delete mode 100644 flutter_modular/rocket.drawio create mode 100644 flutter_modular/test/src/core/models/bind_test.dart create mode 100644 flutter_modular_test/.gitignore create mode 100644 flutter_modular_test/.metadata create mode 100644 flutter_modular_test/CHANGELOG.md create mode 100644 flutter_modular_test/LICENSE create mode 100644 flutter_modular_test/README.md create mode 100644 flutter_modular_test/lib/flutter_modular_test.dart create mode 100644 flutter_modular_test/pubspec.yaml create mode 100644 flutter_modular_test/test/flutter_modular_test_test.dart diff --git a/README.md b/README.md index d23783d8..daf7f3e0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ - [flutter_modular Documentation](https://github.com/Flutterando/modular/tree/master/flutter_modular) +- [flutter_modular_test Documentation](https://github.com/Flutterando/modular/tree/master/flutter_modular_test) + - [modular_codegen Documentation](https://github.com/Flutterando/modular/tree/master/modular_codegen) diff --git a/flutter_modular copy.png b/flutter_modular copy.png deleted file mode 100644 index 7a77c9a50022c255a2d8b63a462f6a9ae8790ab6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38733 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 U6Y-?X615(2Vd>`u&vf4YFA-dQ=>Px# diff --git a/flutter_modular.png b/flutter_modular.png index f10cb1ee9df0dc357cc60420b88ea6a64875ee41..7a77c9a50022c255a2d8b63a462f6a9ae8790ab6 100644 GIT binary patch literal 38733 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 U6Y-?X615(2Vd>`u&vf4YFA-dQ=>Px# literal 25445 zcmeFYXHZm4*EYJzARq`L3L*$1qU4;TNCp*DY+>q8@O2* z@ETGJ3sDKU@PQ7jj2!f+T&ygu?fF~;ssHrL2fib3GgDLjY2siZNG*ySkV;MdC6zeL z&WMVWiHp&Im4lOto0o}|i=Bg)mw}3ng_Vbyg@>7yospG`kAsDejg9J`iyDk(XK2j# z`uU50#sa?tsZAXmZ1|X&ot>SToY|RRb|%cMyu7^3ENskdY>c1~w*N;>Kw-=-dN$0gOf1ML{i~t8 z{D0rn%Ie>(?HweXz$pL7`@ikjUfI>gi21dVJ}srm+79 z+5Y|bf05A8;NJt`8f3S zSUB}q^%(VxdAJ$b4LGF#wV`8PIGBn^bhS^!^0koM}>6sWY+gO_*u@A%m z)0Hx_2Mg``k2NV7+5Yp*(v0d4MEUd#kd`4xZGeP?5fJF_ZL|N4n*V1L`uo1KsS)V( zzd_00X7(^+2WLGyBT*BuB>yugGXFo#z+TVkznA}i29y7{<^M;)2Bvz}CPu*FGE*aG z#Ef)Jf0u{(|Gsknfrzq^i-Vk=tC5}kKS~hOGx?7?{?qPH8wEWpfEZCKdn-LV2Pzvo zn7NUG0~p=T(ZIpc&WP#1V(iZg$lm|k7yd2i-(i{mGvNOs*q^!l7q|Pb=>cDk{QB=8 z0)G5E3>jGiRoHnIb~#_~#C zotWX9xs2r{xVTM`^46o<1}aQty0G*ZMo!^NgKbKKXWv)4O^tiw*-chFgcK?BLL^t~ z>>YafSKViI7^~khfw1Xg%$+@pjJ`gPup7aLp&x_?V({btqknW4I-@{7V;-x9+rh$o z>^qle8!={xC|q~%uClSdt0Y_v4ZrC##AUWpQ$l5#HiDf|4~`E_P(x@U8Xl|9w?}v2 zZjZ;<=)$TJx-jT^mma{)x7pT7AwMcY9~3Iu26t-bE?=dCl`;mNxywXYFTMtoySOed2&OTF21eOe<=uTUEu!1}FyqK2p*_N8{uxXlkI#prIImDCQ&BT|^| z?@ihLn$qx_waf_NE zLN~E*>KNh$^AN*ngkEyb2}QV%T`Sr5RbF8##dBf%;Uc)7nBGXa{xO`?M{MFRTw`8z zhzq5ogHFTY5Blm)8gnu1{YDSyxk$TzqbApWn>rW{CatsciYXw@_HPfp!0=f>HugtO z6VaUO3L3|Zp>7>^B>Cg=3zHs)r?B2VU0R=BEi%74;+BR(FQcTtK~!cJ3M;eqh~YY* zmKZ8$uk?(%b?GX(vx>Psoe{V23LWT42VW!fDF@l_XGM5Z^&$DY&>ejF=4#xz&)!Ct z4!e@7eW1tn5e%qw*9ZsdINPDKgzNX¤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 binds = [ - Bind((i) => LocalStorageSharePreferences()), -]; -``` - -On your test file, you import `flutter_modular_test` and provide your mocked repository in the `initModule` as a replacement of your concrete repository: - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - test('change bind', () { - initModule(AppModule(), changeBinds: [ - Bind((i) => LocalMock()), - ]); - expect(Modular.get(), isA()); - }); -} -``` -## Modular test helper - -Before write in your test file, if you want to improve readability you might to import `flutter_modular_test` and define your mocked module using `IModularTest` and override his methods to create a mock, similar as `ChildModule`, when writing your tests: - -The first step is write a class like that: - -```dart - -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; - -class InitAppModuleHelper extends IModularTest { - - final ModularTestType modularTestType; - IModularTest({this.modularTestType: ModularTestType.resetModule}); - - @override - List binds = [ - Bind((i) => LocalStorageSharePreference()), - ]; - - @override - final ChildModule module = AppModule(); - - - @override - final IModularTest modulardependency = null; - -} - -``` - -The right way to use is writing as least one of that per module, its important to remember to put the modular dependecies in `modularDependency`. its useful because when you load this module for testing, all related modules will be load together. In this case the `AppModule` is the root module and it hasn`t dependency. - -### Load Modular helper on tests - -1. By default when use `IModularTest` each `InitAppModuleHelper().load()` will clean and rebuid the modular and his injects, this is fine to do -each test block independent and make more easy to write modular tests without noise. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - test('change bind', () { - InitAppModuleHelper().load(); - //do something - }); - test('change bind', () { - InitAppModuleHelper().load(); - //do something - }); -} -``` - -2. To keep previous modular and its injects you can pass the param `modularTestType`. -> **NOTE:** With `modularTestType.keepModulesOnMemory`, it won't clean the modules that already have been loaded. (It doesn't call `Modular.removeModule()`) - - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - - test('test1', () { - InitAppModuleHelper().load(); - }); - - test('test2', () { - InitAppModuleHelper( - modularTestType: ModularTestType.keepModulesOnMemory - ).load(); - // Keep the same injects loaded by test1 - }); -} -``` - -3. Changing the binds when `load()` the module like `initModule()`. - -> **NOTE:** It also can change binds of another modules that are its dependencies until find the MainModule. - -Ex: When you have a tree like `InitAppModuleHelper` <- `InitHomeModuleHelper`, when you call `InitHomeModuleHelper.load(changeBinds:[])` it will be able to change binds on `HomeModule` and `AppModule`. Because of that you only need one changeBinds array and it can make all the changes for you, see it on section: [Create helper for a child module](#create-helper-for-a-child-module). - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; - -main() { - - test('test1', () { - InitAppModuleHelper().load(changeBinds:[ - Bind((i) => LocalStorageHive()) - - ]); - }); - -} -``` -### Create helper for a child module -Remember you only need to call the most deeper `IModularTest` and it can load all dependency modules you have added on your mock definition, like the next example: - -The first step is define a `IModularTest` to another module, pay attention that the `HomeModule` is a child of `AppModule`, because of that you need to put the `AppModule` on `modularDependency`. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; -import 'package:flutter_modular/src/inject/bind.dart'; -import 'package:flutter_modular/flutter_modular.dart'; - -import '../../app_module_test_modular.dart'; -import 'home_module.dart'; - -class InitHomeModuleHelper extends IModularTest { - - @override - List get binds => []; - - @override - ChildModule get module => HomeModule(); - - @override - IModularTest get modulardependency => InitAppModuleHelper(); - -} -``` - -Now we can init the `HomeModule` and all his dependencies just by typing `InitHomeModuleHelper().load()` on your `test_file`. It doesn't matter how deep is your module, all dependencies are recursively loaded in a batch, you only need to create a `IModuleTest` for each one and put your dependencies correctly and it will work fine. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'app/modules/home/home_module_test_modular.dart'; -main() { - test('change bind', () { - InitHomeModuleHelper().load(); - //do something - }); - test('change bind', () { - InitHomeModuleHelper().load(); - //do something - }); -} -``` - -### Mocking with mockito - -1. Add the mock into the `binds` list on your `IModularTest` helper, if you dont need to change during the tests. - -```dart -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_modular/src/interfaces/child_module.dart'; -import 'package:flutter_modular/src/inject/bind.dart'; -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:mockito/mockito.dart'; - -import '../../app_module_test_modular.dart'; -import 'home_module.dart'; - -class LocalStorageMock extends Mock implements ILocalStorage {} - -class InitHomeModuleHelper extends IModularTest { - - @override - List get binds => [ - Bind((i) => LocalStorageMock()), - ]; - - @override - ChildModule get module => HomeModule(); - - @override - IModularTest get modulardependency => InitAppModuleHelper(); - -} - - -``` - -2. Get the instance using `Modular.get()` and change the behavior as you need in the middle of the test: - -```dart -import 'package:flutter_modular/flutter_modular.dart'; -import 'package:flutter_modular/flutter_modular_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -import 'app/modules/home/home_module_test_modular.dart'; - -class LocalStorageMock extends Mock implements ILocalStorage {} - -main() { - - LocalStorageMock localStorageMock = LocalStorageMock(); - - group("IModuleTest", () { - setUp(() { - InitAppModuleHelper().load(changeBinds:[ - - Bind((i) => localStorageMock), - - ]); - ILocalStorage iLocalStorage = Modular.get(); - }); - - test('change bind', () { - when(localStorageMock.doSomething()).thenReturn("Hello"); - iLocalStorage.doSomething(); - //return Hello - - when(localStorageMock.doSomething()).thenReturn("World"); - iLocalStorage.doSomething(); - //return World - }); - - }); - -} -``` ### Mock the navigation system We though it would be interesting to provide a native way to mock the navigation system when used with `Modular.to` and `Modular.link`. To do this, you may just implement `IModularNavigator` and pass your implementation to `Modular.navigatorDelegate`. diff --git a/flutter_modular/lib/flutter_modular.dart b/flutter_modular/lib/flutter_modular.dart index 48f4ce57..a874af06 100644 --- a/flutter_modular/lib/flutter_modular.dart +++ b/flutter_modular/lib/flutter_modular.dart @@ -1,18 +1,19 @@ library flutter_modular; export 'package:flutter_modular_annotations/flutter_modular_annotations.dart'; -export 'src/core/inject/bind.dart'; -export 'src/core/inject/inject.dart'; + +export 'src/core/interfaces/child_module.dart'; export 'src/core/interfaces/disposable.dart'; export 'src/core/interfaces/modular_route.dart'; export 'src/core/interfaces/route_guard.dart'; +export 'src/core/models/bind.dart'; export 'src/core/models/child_route.dart'; export 'src/core/models/custom_transition.dart'; export 'src/core/models/modular_arguments.dart'; export 'src/core/models/module_route.dart'; export 'src/core/models/wildcard_route.dart'; -export 'src/core/modules/child_module.dart'; -export 'src/core/modules/main_module.dart'; +export 'src/presenters/inject.dart'; +export 'src/presenters/main_module.dart'; export 'src/presenters/modular_base.dart'; export 'src/presenters/widgets/modular_app.dart'; export 'src/presenters/widgets/modular_state.dart'; diff --git a/flutter_modular/lib/flutter_modular_test.dart b/flutter_modular/lib/flutter_modular_test.dart deleted file mode 100644 index 6372b1a0..00000000 --- a/flutter_modular/lib/flutter_modular_test.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'src/test/modular_test_interface.dart'; -export 'src/test/utils_test.dart'; diff --git a/flutter_modular/lib/src/core/inject/bind.dart b/flutter_modular/lib/src/core/inject/bind.dart deleted file mode 100644 index e1fe65c4..00000000 --- a/flutter_modular/lib/src/core/inject/bind.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'inject.dart'; - -class Bind { - final T Function(Inject i) inject; - - ///single instance object? - final bool singleton; - - ///When 'true', the object is instantiated only the first time it is called. - ///When 'false', the object is instantiated along with the module. - final bool lazy; - - Bind(this.inject, {this.singleton = true, this.lazy = true}) - : assert((singleton || lazy), - r"'singleton' can't be false if 'lazy' is also false"); - - ///Bind an already exist 'Instance' of object.. - factory Bind.instance(T instance) { - return Bind((i) => instance, singleton: false, lazy: true); - } - - ///Bind a 'Singleton' class. - ///Built together with the module. - ///The instance will always be the same. - factory Bind.singleton(T Function(Inject i) inject) { - return Bind(inject, singleton: true, lazy: false); - } - - ///Bind a 'Lazy Singleton' class. - ///Built only when called the first time using Modular.get. - ///The instance will always be the same. - factory Bind.lazySingleton(T Function(Inject i) inject) { - return Bind(inject, singleton: true, lazy: true); - } - - ///Bind a factory. Always a new constructor when calling Modular.get - factory Bind.factory(T Function(Inject i) inject) { - return Bind(inject, singleton: false, lazy: true); - } -} - -class BindInject extends Bind { - final T Function(Inject i) inject; - - ///single instance object? - final bool singleton; - - ///When 'true', the object is instantiated only the first time it is called. - ///When 'false', the object is instantiated along with the module. - final bool lazy; - - BindInject(this.inject, {this.singleton = true, this.lazy = true}) - : super(inject, singleton: singleton, lazy: lazy); -} - -class BindEmpty extends Bind { - BindEmpty() : super((e) => Object()); -} diff --git a/flutter_modular/lib/src/core/modules/child_module.dart b/flutter_modular/lib/src/core/interfaces/child_module.dart similarity index 81% rename from flutter_modular/lib/src/core/modules/child_module.dart rename to flutter_modular/lib/src/core/interfaces/child_module.dart index fe3e655e..491df997 100644 --- a/flutter_modular/lib/src/core/modules/child_module.dart +++ b/flutter_modular/lib/src/core/interfaces/child_module.dart @@ -1,10 +1,10 @@ import 'package:flutter/widgets.dart'; +import '../../presenters/inject.dart'; import '../errors/errors.dart'; -import '../inject/bind.dart'; -import '../inject/inject.dart'; -import '../interfaces/disposable.dart'; -import '../interfaces/modular_route.dart'; +import '../models/bind.dart'; +import 'disposable.dart'; +import 'modular_route.dart'; @immutable abstract class ChildModule { @@ -21,8 +21,7 @@ abstract class ChildModule { final Map _singletonBinds = {}; - T? getBind( - {Map? params, required List typesInRequest}) { + T? getBind({Map? params, required List typesInRequest}) { T bindValue; var type = _getInjectType(); if (_singletonBinds.containsKey(type)) { @@ -30,8 +29,7 @@ abstract class ChildModule { return bindValue; } - var bind = binds.firstWhere((b) => b.inject is T Function(Inject), - orElse: () => BindEmpty()); + var bind = binds.firstWhere((b) => b.inject is T Function(Inject), orElse: () => BindEmpty()); if (bind is BindEmpty) { typesInRequest.remove(type); return null; @@ -50,9 +48,8 @@ ${typesInRequest.join('\n')} typesInRequest.add(type); } - bindValue = - bind.inject(Inject(params: params, typesInRequest: typesInRequest)); - if (bind.singleton) { + bindValue = bind.inject(Inject(params: params, typesInRequest: typesInRequest)) as T; + if (bind.isSingleton) { _singletonBinds[type] = bindValue; } @@ -74,7 +71,7 @@ ${typesInRequest.join('\n')} } _callDispose(dynamic bind) { - if (bind is Disposable || bind is ChangeNotifier) { + if (bind is Disposable) { bind.dispose(); return; } else if (bind is Sink) { @@ -106,7 +103,7 @@ ${typesInRequest.join('\n')} /// Create a instance of all binds isn't lazy Loaded void instance() { for (final bindElement in binds) { - if (!bindElement.lazy) { + if (!bindElement.isLazy) { var b = bindElement.inject(Inject()); _singletonBinds[b.runtimeType] = b; } diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart b/flutter_modular/lib/src/core/interfaces/modular_interface.dart similarity index 83% rename from flutter_modular/lib/src/presenters/interfaces/modular_interface.dart rename to flutter_modular/lib/src/core/interfaces/modular_interface.dart index 09a87870..ee465de9 100644 --- a/flutter_modular/lib/src/presenters/interfaces/modular_interface.dart +++ b/flutter_modular/lib/src/core/interfaces/modular_interface.dart @@ -1,5 +1,5 @@ -import '../../core/models/modular_arguments.dart'; -import '../../core/modules/child_module.dart'; +import '../models/modular_arguments.dart'; +import 'child_module.dart'; import 'modular_navigator_interface.dart'; abstract class ModularInterface { diff --git a/flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart b/flutter_modular/lib/src/core/interfaces/modular_navigator_interface.dart similarity index 100% rename from flutter_modular/lib/src/presenters/interfaces/modular_navigator_interface.dart rename to flutter_modular/lib/src/core/interfaces/modular_navigator_interface.dart diff --git a/flutter_modular/lib/src/core/interfaces/modular_route.dart b/flutter_modular/lib/src/core/interfaces/modular_route.dart index 2fffb092..d0fbe05e 100644 --- a/flutter_modular/lib/src/core/interfaces/modular_route.dart +++ b/flutter_modular/lib/src/core/interfaces/modular_route.dart @@ -1,13 +1,18 @@ import 'dart:async'; +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import '../models/custom_transition.dart'; import '../models/modular_arguments.dart'; -import '../models/modular_route_impl.dart'; -import '../modules/child_module.dart'; +import 'child_module.dart'; import 'route_guard.dart'; +typedef RouteBuilder = MaterialPageRoute Function( + WidgetBuilder, RouteSettings); +typedef ModularChild = Widget Function( + BuildContext context, ModularArguments? args); + abstract class ModularRoute { ChildModule? get currentModule; diff --git a/flutter_modular/lib/src/core/models/bind.dart b/flutter_modular/lib/src/core/models/bind.dart new file mode 100644 index 00000000..f01e74fa --- /dev/null +++ b/flutter_modular/lib/src/core/models/bind.dart @@ -0,0 +1,55 @@ +import '../../presenters/inject.dart'; + +class Bind { + final T Function(Inject i) inject; + + ///single instance object? + final bool isSingleton; + + ///When 'true', the object is instantiated only the first time it is called. + ///When 'false', the object is instantiated along with the module. + final bool isLazy; + + Bind(this.inject, {this.isSingleton = true, this.isLazy = true}) : assert((isSingleton || isLazy), r"'singleton' can't be false if 'lazy' is also false"); + + ///Bind an already exist 'Instance' of object.. + static Bind instance(T instance) { + return Bind((i) => instance, isSingleton: false, isLazy: true); + } + + ///Bind a 'Singleton' class. + ///Built together with the module. + ///The instance will always be the same. + static Bind singleton(T Function(Inject i) inject) { + return Bind(inject, isSingleton: true, isLazy: false); + } + + ///Bind a 'Lazy Singleton' class. + ///Built only when called the first time using Modular.get. + ///The instance will always be the same. + static Bind lazySingleton(T Function(Inject i) inject) { + return Bind(inject, isSingleton: true, isLazy: true); + } + + ///Bind a factory. Always a new constructor when calling Modular.get + static Bind factory(T Function(Inject i) inject) { + return Bind(inject, isSingleton: false, isLazy: true); + } +} + +class BindInject extends Bind { + final T Function(Inject i) inject; + + ///single instance object? + final bool isSingleton; + + ///When 'true', the object is instantiated only the first time it is called. + ///When 'false', the object is instantiated along with the module. + final bool isLazy; + + BindInject(this.inject, {this.isSingleton = true, this.isLazy = true}) : super(inject, isSingleton: isSingleton, isLazy: isLazy); +} + +class BindEmpty extends Bind { + BindEmpty() : super((e) => Object()); +} diff --git a/flutter_modular/lib/src/core/models/child_route.dart b/flutter_modular/lib/src/core/models/child_route.dart index a952ea62..5b7c56bc 100644 --- a/flutter_modular/lib/src/core/models/child_route.dart +++ b/flutter_modular/lib/src/core/models/child_route.dart @@ -4,7 +4,7 @@ import '../interfaces/modular_route.dart'; import '../interfaces/route_guard.dart'; import 'custom_transition.dart'; import 'modular_arguments.dart'; -import 'modular_route_impl.dart'; +import '../../presenters/modular_route_impl.dart'; class ChildRoute extends ModularRouteImpl { ChildRoute( diff --git a/flutter_modular/lib/src/core/models/module_route.dart b/flutter_modular/lib/src/core/models/module_route.dart index 77133e1d..eb22b0e8 100644 --- a/flutter_modular/lib/src/core/models/module_route.dart +++ b/flutter_modular/lib/src/core/models/module_route.dart @@ -1,8 +1,8 @@ +import '../../presenters/modular_route_impl.dart'; +import 'custom_transition.dart'; +import '../interfaces/child_module.dart'; import '../interfaces/modular_route.dart'; import '../interfaces/route_guard.dart'; -import '../modules/child_module.dart'; -import 'custom_transition.dart'; -import 'modular_route_impl.dart'; class ModuleRoute extends ModularRouteImpl { ModuleRoute( diff --git a/flutter_modular/lib/src/core/models/wildcard_route.dart b/flutter_modular/lib/src/core/models/wildcard_route.dart index 7fbfc5ba..9ee4a073 100644 --- a/flutter_modular/lib/src/core/models/wildcard_route.dart +++ b/flutter_modular/lib/src/core/models/wildcard_route.dart @@ -4,7 +4,7 @@ import '../interfaces/modular_route.dart'; import '../interfaces/route_guard.dart'; import 'custom_transition.dart'; import 'modular_arguments.dart'; -import 'modular_route_impl.dart'; +import '../../presenters/modular_route_impl.dart'; class WildcardRoute extends ModularRouteImpl { WildcardRoute({ diff --git a/flutter_modular/lib/src/core/inject/inject.dart b/flutter_modular/lib/src/presenters/inject.dart similarity index 90% rename from flutter_modular/lib/src/core/inject/inject.dart rename to flutter_modular/lib/src/presenters/inject.dart index b28b68d7..53bf2074 100644 --- a/flutter_modular/lib/src/core/inject/inject.dart +++ b/flutter_modular/lib/src/presenters/inject.dart @@ -1,5 +1,6 @@ -import '../../presenters/modular_base.dart'; -import '../models/modular_arguments.dart'; +import 'modular_base.dart'; + +import '../core/models/modular_arguments.dart'; class Inject { ///!!!!NOT RECOMMENDED USE!!!! diff --git a/flutter_modular/lib/src/core/modules/main_module.dart b/flutter_modular/lib/src/presenters/main_module.dart similarity index 72% rename from flutter_modular/lib/src/core/modules/main_module.dart rename to flutter_modular/lib/src/presenters/main_module.dart index a4e9cff7..31f1b1b5 100644 --- a/flutter_modular/lib/src/core/modules/main_module.dart +++ b/flutter_modular/lib/src/presenters/main_module.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; -import 'child_module.dart'; +import '../core/interfaces/child_module.dart'; abstract class MainModule extends ChildModule { late final Widget bootstrap; diff --git a/flutter_modular/lib/src/presenters/modular_base.dart b/flutter_modular/lib/src/presenters/modular_base.dart index cdab2fac..ef1972a8 100644 --- a/flutter_modular/lib/src/presenters/modular_base.dart +++ b/flutter_modular/lib/src/presenters/modular_base.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import '../../flutter_modular.dart'; -import '../core/modules/child_module.dart'; -import 'interfaces/modular_interface.dart'; +import '../core/interfaces/child_module.dart'; +import '../core/interfaces/modular_interface.dart'; import 'modular_impl.dart'; import 'navigation/modular_route_information_parser.dart'; import 'navigation/modular_router_delegate.dart'; diff --git a/flutter_modular/lib/src/presenters/modular_impl.dart b/flutter_modular/lib/src/presenters/modular_impl.dart index fa551fa2..029fca94 100644 --- a/flutter_modular/lib/src/presenters/modular_impl.dart +++ b/flutter_modular/lib/src/presenters/modular_impl.dart @@ -2,9 +2,9 @@ import 'package:flutter/foundation.dart'; import '../core/errors/errors.dart'; import '../core/models/modular_arguments.dart'; -import '../core/modules/child_module.dart'; -import 'interfaces/modular_interface.dart'; -import 'interfaces/modular_navigator_interface.dart'; +import '../core/interfaces/child_module.dart'; +import '../core/interfaces/modular_interface.dart'; +import '../core/interfaces/modular_navigator_interface.dart'; import 'modular_base.dart'; import 'navigation/modular_router_delegate.dart'; @@ -63,10 +63,7 @@ class ModularImpl implements ModularInterface { String get initialRoute => '/'; @override - B get( - {Map params = const {}, - List? typesInRequestList, - B? defaultValue}) { + B get({Map params = const {}, List? typesInRequestList, B? defaultValue}) { var typesInRequest = typesInRequestList ?? []; if (B.toString() == 'dynamic') { throw ModularError('not allow for dynamic values'); @@ -74,12 +71,8 @@ class ModularImpl implements ModularInterface { B? result; if (typesInRequest.isEmpty) { - final module = routerDelegate - .currentConfiguration?.currentModule?.runtimeType - .toString() ?? - '=global'; - result = _getInjectableObject(module, - params: params, typesInRequestList: typesInRequest); + final module = routerDelegate.currentConfiguration?.currentModule?.runtimeType.toString() ?? '=global'; + result = _getInjectableObject(module, params: params, typesInRequestList: typesInRequest); } if (result != null) { @@ -87,8 +80,7 @@ class ModularImpl implements ModularInterface { } for (var key in injectMap.keys) { - final value = _getInjectableObject(key, - params: params, typesInRequestList: typesInRequest, checkKey: false); + final value = _getInjectableObject(key, params: params, typesInRequestList: typesInRequest, checkKey: false); if (value != null) { return value; } @@ -101,7 +93,7 @@ class ModularImpl implements ModularInterface { throw ModularError('${B.toString()} not found'); } - B? _getInjectableObject( + B? _getInjectableObject( String tag, { Map params = const {}, List? typesInRequestList, @@ -110,11 +102,9 @@ class ModularImpl implements ModularInterface { B? value; var typesInRequest = typesInRequestList ?? []; if (!checkKey) { - value = injectMap[tag] - ?.getBind(params: params, typesInRequest: typesInRequest); + value = injectMap[tag]?.getBind(params: params, typesInRequest: typesInRequest); } else if (injectMap.containsKey(tag)) { - value = injectMap[tag] - ?.getBind(params: params, typesInRequest: typesInRequest); + value = injectMap[tag]?.getBind(params: params, typesInRequest: typesInRequest); } return value; diff --git a/flutter_modular/lib/src/core/models/modular_route_impl.dart b/flutter_modular/lib/src/presenters/modular_route_impl.dart similarity index 94% rename from flutter_modular/lib/src/core/models/modular_route_impl.dart rename to flutter_modular/lib/src/presenters/modular_route_impl.dart index 13c5166a..00e27d87 100644 --- a/flutter_modular/lib/src/core/models/modular_route_impl.dart +++ b/flutter_modular/lib/src/presenters/modular_route_impl.dart @@ -2,18 +2,15 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../interfaces/modular_route.dart'; -import '../interfaces/route_guard.dart'; -import '../modules/child_module.dart'; -import '../transitions/transitions.dart'; -import 'custom_transition.dart'; -import 'modular_arguments.dart'; +import '../core/interfaces/child_module.dart'; +import '../core/interfaces/modular_route.dart'; +import '../core/interfaces/route_guard.dart'; +import '../core/models/custom_transition.dart'; +import '../core/models/modular_arguments.dart'; +import 'transitions/transitions.dart'; + -typedef RouteBuilder = MaterialPageRoute Function( - WidgetBuilder, RouteSettings); -typedef ModularChild = Widget Function( - BuildContext context, ModularArguments? args); class ModularRouteImpl extends ModularRoute { @override diff --git a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart index 7dd11fa4..fa73ab18 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_route_information_parser.dart @@ -3,7 +3,7 @@ import 'package:flutter_modular/src/core/interfaces/route_guard.dart'; import '../../core/errors/errors.dart'; import '../../core/interfaces/modular_route.dart'; -import '../../core/modules/child_module.dart'; +import '../../core/interfaces/child_module.dart'; import '../modular_base.dart'; class ModularRouteInformationParser diff --git a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart index 7817c6d3..08a594d6 100644 --- a/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart +++ b/flutter_modular/lib/src/presenters/navigation/modular_router_delegate.dart @@ -3,8 +3,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; import '../../core/interfaces/modular_route.dart'; -import '../../core/modules/child_module.dart'; -import '../interfaces/modular_navigator_interface.dart'; +import '../../core/interfaces/child_module.dart'; +import '../../core/interfaces/modular_navigator_interface.dart'; import '../modular_base.dart'; import 'custom_navigator.dart'; import 'modular_page.dart'; diff --git a/flutter_modular/lib/src/core/transitions/page_transition.dart b/flutter_modular/lib/src/presenters/transitions/page_transition.dart similarity index 100% rename from flutter_modular/lib/src/core/transitions/page_transition.dart rename to flutter_modular/lib/src/presenters/transitions/page_transition.dart diff --git a/flutter_modular/lib/src/core/transitions/transitions.dart b/flutter_modular/lib/src/presenters/transitions/transitions.dart similarity index 98% rename from flutter_modular/lib/src/core/transitions/transitions.dart rename to flutter_modular/lib/src/presenters/transitions/transitions.dart index 1ee4c1cf..cda250cf 100644 --- a/flutter_modular/lib/src/core/transitions/transitions.dart +++ b/flutter_modular/lib/src/presenters/transitions/transitions.dart @@ -1,5 +1,5 @@ import 'package:flutter/widgets.dart'; -import '../models/modular_arguments.dart'; +import 'package:flutter_modular/flutter_modular.dart'; import 'page_transition.dart'; diff --git a/flutter_modular/lib/src/presenters/widgets/modular_app.dart b/flutter_modular/lib/src/presenters/widgets/modular_app.dart index 81fe113d..b248b2ab 100644 --- a/flutter_modular/lib/src/presenters/widgets/modular_app.dart +++ b/flutter_modular/lib/src/presenters/widgets/modular_app.dart @@ -1,5 +1,5 @@ import 'package:flutter/widgets.dart'; -import '../../core/modules/main_module.dart'; +import '../main_module.dart'; import '../modular_base.dart'; diff --git a/flutter_modular/lib/src/presenters/widgets/widget_module.dart b/flutter_modular/lib/src/presenters/widgets/widget_module.dart index 6f9b1694..2f8f9466 100644 --- a/flutter_modular/lib/src/presenters/widgets/widget_module.dart +++ b/flutter_modular/lib/src/presenters/widgets/widget_module.dart @@ -1,8 +1,8 @@ import 'package:flutter/widgets.dart'; import '../../../flutter_modular.dart'; -import '../../core/inject/bind.dart'; -import '../../core/modules/child_module.dart'; +import '../../core/models/bind.dart'; +import '../../core/interfaces/child_module.dart'; import '../modular_base.dart'; _debugPrintModular(String text) { @@ -34,10 +34,8 @@ abstract class WidgetModule extends StatelessWidget implements ChildModule { } @override - T? getBind( - {Map? params, List typesInRequest = const []}) { - return _fakeModule.getBind( - params: params, typesInRequest: typesInRequest); + T? getBind({Map? params, List typesInRequest = const []}) { + return _fakeModule.getBind(params: params, typesInRequest: typesInRequest); } @override @@ -83,8 +81,7 @@ class ModularProvider extends StatefulWidget { final ChildModule module; final Widget child; - const ModularProvider({Key? key, required this.module, required this.child}) - : super(key: key); + const ModularProvider({Key? key, required this.module, required this.child}) : super(key: key); @override _ModularProviderState createState() => _ModularProviderState(); diff --git a/flutter_modular/lib/src/test/modular_test_interface.dart b/flutter_modular/lib/src/test/modular_test_interface.dart deleted file mode 100644 index 0c649610..00000000 --- a/flutter_modular/lib/src/test/modular_test_interface.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../core/inject/bind.dart'; -import '../core/modules/child_module.dart'; -import '../core/modules/main_module.dart'; -import 'utils_test.dart'; - -enum ModularTestType { resetModules, keepModulesOnMemory } - -abstract class IModularTest { - final ModularTestType modularTestType; - IModularTest({this.modularTestType = ModularTestType.resetModules}); - - ChildModule get module; - List get binds; - IModularTest get modulardependency; - - void load({ - IModularTest? changedependency, - List? changeBinds, - bool isLoadDependency = true, - }) { - final dependency = getDendencies( - changedependency: changedependency, - isLoadDependency: isLoadDependency, - ); - final binds = getBinds(changeBinds); - memoryManage(modularTestType); - loadModularDependency( - isLoadDependency: isLoadDependency, - changeBinds: changeBinds, - dependency: dependency, - ); - - initModule(module, changeBinds: binds, initialModule: isMainModule); - } - - @visibleForTesting - IModularTest getDendencies({ - IModularTest? changedependency, - required bool isLoadDependency, - }) { - changedependency ??= modulardependency; - - assert( - !_isDependencyRequired(changedependency, isLoadDependency), - "Dependency must not be null when isLoadDependency is true", - ); - return changedependency; - } - - bool _isDependencyRequired(IModularTest? dependency, bool isLoadDependency) => - dependency == null && isLoadDependency && isMainModule; - - @visibleForTesting - List getBinds(List? changeBinds) { - final mergedChangeBinds = mergeBinds(changeBinds, binds); - - return mergedChangeBinds; - } - - @visibleForTesting - List mergeBinds(List? changeBinds, List? defaultBinds) { - final resultBinds = defaultBinds ?? []; - - for (var bind in (changeBinds ?? [])) { - var changedBind = resultBinds.firstWhere( - (item) => item.runtimeType == bind.runtimeType, - orElse: () => BindEmpty(), - ); - - if (changedBind is! BindEmpty) resultBinds.remove(changedBind); - resultBinds.add(bind); - } - - return resultBinds; - } - - @visibleForTesting - void memoryManage(ModularTestType modularTestType) { - if (modularTestType == ModularTestType.resetModules) { - // Modular.removeModule(module); - } - } - - @visibleForTesting - void loadModularDependency({ - required bool isLoadDependency, - required List? changeBinds, - required IModularTest? dependency, - }) { - if (isLoadDependency && dependency != null) { - dependency.load(changeBinds: changeBinds); - } - } - - bool get isMainModule => !(module is MainModule); -} diff --git a/flutter_modular/lib/src/test/utils_test.dart b/flutter_modular/lib/src/test/utils_test.dart deleted file mode 100644 index dda5da23..00000000 --- a/flutter_modular/lib/src/test/utils_test.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../core/inject/bind.dart'; -import '../core/modules/child_module.dart'; - -void initModule(ChildModule module, - {List changeBinds = const [], bool initialModule = false}) { - //Modular.debugMode = false; - final list = module.binds; - final changedList = List.from(list); - for (var item in list) { - var dep = (changeBinds).firstWhere((dep) { - return item.runtimeType == dep.runtimeType; - }, orElse: () => BindEmpty()); - if (dep is BindEmpty) { - changedList.remove(item); - changedList.add(dep); - } - } - module.changeBinds(changedList); - if (initialModule) { - // Modular.init(module); - } else { - // Modular.bindModule(module); - } -} - -void initModules(List modules, - {List changeBinds = const []}) { - for (var module in modules) { - initModule(module, changeBinds: changeBinds); - } -} - -Widget buildTestableWidget(Widget widget) { - return MediaQuery( - data: MediaQueryData(), - child: MaterialApp( - home: widget, - initialRoute: '/', - // navigatorKey: Modular.navigatorKey, - // onGenerateRoute: Modular.generateRoute, - ), - ); -} diff --git a/flutter_modular/pubspec.yaml b/flutter_modular/pubspec.yaml index 5524b7b5..657cd911 100644 --- a/flutter_modular/pubspec.yaml +++ b/flutter_modular/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_modular description: Smart project structure with dependency injection and route management -version: 3.0.0-nullsafety.17 +version: 3.0.0-nullsafety.19 homepage: https://github.com/Flutterando/modular environment: diff --git a/flutter_modular/rocket.drawio b/flutter_modular/rocket.drawio deleted file mode 100644 index 16356d3b..00000000 --- a/flutter_modular/rocket.drawio +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/flutter_modular/test/src/core/inject/bind_test.dart b/flutter_modular/test/src/core/inject/bind_test.dart index 4e6d8f32..2527ebc1 100644 --- a/flutter_modular/test/src/core/inject/bind_test.dart +++ b/flutter_modular/test/src/core/inject/bind_test.dart @@ -1,10 +1,9 @@ -import 'package:flutter_modular/src/core/inject/bind.dart'; +import 'package:flutter_modular/src/core/models/bind.dart'; import 'package:flutter_test/flutter_test.dart'; main() { test('singleton can\'t be false if \'lazy\' is also false', () { - expect(() => Bind((i) => String, lazy: false, singleton: false), - throwsAssertionError); + expect(() => Bind((i) => String, isLazy: false, isSingleton: false), throwsAssertionError); }); test('factories', () { diff --git a/flutter_modular/test/src/core/models/bind_test.dart b/flutter_modular/test/src/core/models/bind_test.dart new file mode 100644 index 00000000..b4690779 --- /dev/null +++ b/flutter_modular/test/src/core/models/bind_test.dart @@ -0,0 +1,18 @@ +import 'package:flutter_modular/src/core/models/bind.dart'; +import 'package:flutter_test/flutter_test.dart'; + +main() { + test('check type', () { + final bind = Bind.instance('teste'); + expect(bind, isA>()); + }); + + test('check type in list', () { + final binds = [ + Bind.instance('teste'), + Bind.instance(true), + ]; + + // expect(bind, isA>()); + }); +} diff --git a/flutter_modular/test/src/core/models/modular_router_test.dart b/flutter_modular/test/src/core/models/modular_router_test.dart index e6322fa2..bdd38c82 100644 --- a/flutter_modular/test/src/core/models/modular_router_test.dart +++ b/flutter_modular/test/src/core/models/modular_router_test.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_modular/src/core/interfaces/modular_route.dart'; import 'package:flutter_modular/src/core/models/custom_transition.dart'; -import 'package:flutter_modular/src/core/models/modular_route_impl.dart'; +import 'package:flutter_modular/src/presenters/modular_route_impl.dart'; import 'package:flutter_test/flutter_test.dart'; import '../modules/child_module_test.dart'; diff --git a/flutter_modular/test/src/core/modules/child_module_test.dart b/flutter_modular/test/src/core/modules/child_module_test.dart index 43d70d27..2bfad699 100644 --- a/flutter_modular/test/src/core/modules/child_module_test.dart +++ b/flutter_modular/test/src/core/modules/child_module_test.dart @@ -3,18 +3,18 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/src/core/errors/errors.dart'; -import 'package:flutter_modular/src/core/inject/bind.dart'; -import 'package:flutter_modular/src/core/modules/child_module.dart'; +import 'package:flutter_modular/src/core/models/bind.dart'; +import 'package:flutter_modular/src/core/interfaces/child_module.dart'; import 'package:flutter_test/flutter_test.dart'; class ModuleMock extends ChildModule { @override final List binds = [ Bind((i) => "Test"), - Bind.instance(1), - Bind((i) => true, lazy: false), - Bind((i) => StreamController(), lazy: false), - Bind((i) => ValueNotifier(0), lazy: false), + Bind.instance(1), + Bind((i) => true, isLazy: false), + Bind((i) => StreamController(), isLazy: false), + Bind((i) => ValueNotifier(0), isLazy: false), ]; @override @@ -53,10 +53,8 @@ main() { expect(module.getBind(typesInRequest: []), null); }); - test('should throw exception when exist value over in the injection search', - () { - expect(() => module.getBind(typesInRequest: [bool]), - throwsA(isA())); + test('should throw exception when exist value over in the injection search', () { + expect(() => module.getBind(typesInRequest: [bool]), throwsA(isA())); }); test('should Create a instance of all binds isn\'t lazy Loaded', () { @@ -69,49 +67,33 @@ main() { expect(module.getBind(typesInRequest: [bool]), equals(true)); module.remove(); - expect(() => module.getBind(typesInRequest: [bool]), - throwsA(isA())); + expect(() => module.getBind(typesInRequest: [bool]), throwsA(isA())); //Stream - expect(module.getBind(typesInRequest: [StreamController]), - isA()); + expect(module.getBind(typesInRequest: [StreamController]), isA()); module.remove(); - expect( - () => module - .getBind(typesInRequest: [StreamController]), - throwsA(isA())); + expect(() => module.getBind(typesInRequest: [StreamController]), throwsA(isA())); //ChangeNotifier - expect(module.getBind(typesInRequest: [ChangeNotifier]), - isA()); + expect(module.getBind(typesInRequest: [ChangeNotifier]), isA()); module.remove(); - expect( - () => module.getBind(typesInRequest: [ChangeNotifier]), - throwsA(isA())); + expect(() => module.getBind(typesInRequest: [ChangeNotifier]), throwsA(isA())); }); test('should clean all injections', () { module.instance(); expect(module.getBind(typesInRequest: [bool]), equals(true)); - expect(module.getBind(typesInRequest: [StreamController]), - isA()); - expect(module.getBind(typesInRequest: [ChangeNotifier]), - isA()); + expect(module.getBind(typesInRequest: [StreamController]), isA()); + expect(module.getBind(typesInRequest: [ChangeNotifier]), isA()); module.cleanInjects(); - expect(() => module.getBind(typesInRequest: [bool]), - throwsA(isA())); + expect(() => module.getBind(typesInRequest: [bool]), throwsA(isA())); - expect( - () => module - .getBind(typesInRequest: [StreamController]), - throwsA(isA())); + expect(() => module.getBind(typesInRequest: [StreamController]), throwsA(isA())); - expect( - () => module.getBind(typesInRequest: [ChangeNotifier]), - throwsA(isA())); + expect(() => module.getBind(typesInRequest: [ChangeNotifier]), throwsA(isA())); }); } diff --git a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart index dfe72cea..42b074ca 100644 --- a/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart +++ b/flutter_modular/test/src/presenters/navigation/modular_route_information_parse_test.dart @@ -40,8 +40,7 @@ main() { }); test('should guard router /401', () async { - expect(parse.selectRoute('/401', ModuleMock()), - throwsA(isA())); + expect(parse.selectRoute('/401', ModuleMock()), throwsA(isA())); }); }); @@ -81,13 +80,11 @@ main() { }); test('should guard router /mock/listguarded', () async { - expect(parse.selectRoute('/mock/listguarded', ModuleMock()), - throwsA(isA())); + expect(parse.selectRoute('/mock/listguarded', ModuleMock()), throwsA(isA())); }); test('should guard router /guarded/list', () async { - expect(parse.selectRoute('/guarded/list', ModuleMock()), - throwsA(isA())); + expect(parse.selectRoute('/guarded/list', ModuleMock()), throwsA(isA())); }); }); @@ -107,15 +104,11 @@ main() { expect(route.child!(context, null), isA()); expect(route.path, '/home'); expect(route.routerOutlet.length, 1); - expect( - route.routerOutlet[0].child!(context, route.routerOutlet[0].args) - .toString(), - '3'); + expect(route.routerOutlet[0].child!(context, route.routerOutlet[0].args).toString(), '3'); expect(route.routerOutlet[0].path, '/home/tab2/3'); }); test('should throw error if not exist route /home/tab3', () async { - expect(parse.selectRoute('/home/tab3', ModuleMock()), - throwsA(isA())); + expect(parse.selectRoute('/home/tab3', ModuleMock()), throwsA(isA())); }); test('should retrive router (Module)', () async { @@ -129,21 +122,15 @@ main() { expect(route.routerOutlet[0].path, '/mock/home'); }); }); - - test('should resolve Outlet Module Path', () async { - expect(parse.resolveOutletModulePath('/home', '/'), '/home'); - expect( - parse.resolveOutletModulePath('/home/', '/home/start'), '/home/start'); - }); } class ModuleMock extends ChildModule { @override final List binds = [ Bind((i) => "Test"), - Bind((i) => true, lazy: false), - Bind((i) => StreamController(), lazy: false), - Bind((i) => ValueNotifier(0), lazy: false), + Bind((i) => true, isLazy: false), + Bind((i) => StreamController(), isLazy: false), + Bind((i) => ValueNotifier(0), isLazy: false), ]; @override @@ -187,9 +174,9 @@ class ModuleMock2 extends ChildModule { @override final List binds = [ Bind((i) => "Test"), - Bind((i) => true, lazy: false), - Bind((i) => StreamController(), lazy: false), - Bind((i) => ValueNotifier(0), lazy: false), + Bind((i) => true, isLazy: false), + Bind((i) => StreamController(), isLazy: false), + Bind((i) => ValueNotifier(0), isLazy: false), ]; @override @@ -220,9 +207,9 @@ class ModuleGuarded extends ChildModule { @override final List binds = [ Bind((i) => "Test"), - Bind((i) => true, lazy: false), - Bind((i) => StreamController(), lazy: false), - Bind((i) => ValueNotifier(0), lazy: false), + Bind((i) => true, isLazy: false), + Bind((i) => StreamController(), isLazy: false), + Bind((i) => ValueNotifier(0), isLazy: false), ]; @override diff --git a/flutter_modular_test/.gitignore b/flutter_modular_test/.gitignore new file mode 100644 index 00000000..1985397a --- /dev/null +++ b/flutter_modular_test/.gitignore @@ -0,0 +1,74 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/flutter_modular_test/.metadata b/flutter_modular_test/.metadata new file mode 100644 index 00000000..4d40dac7 --- /dev/null +++ b/flutter_modular_test/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 022b333a089afb81c471ec43d1f1f4f26305d876 + channel: beta + +project_type: package diff --git a/flutter_modular_test/CHANGELOG.md b/flutter_modular_test/CHANGELOG.md new file mode 100644 index 00000000..ac071598 --- /dev/null +++ b/flutter_modular_test/CHANGELOG.md @@ -0,0 +1,3 @@ +## [0.0.1] - TODO: Add release date. + +* TODO: Describe initial release. diff --git a/flutter_modular_test/LICENSE b/flutter_modular_test/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/flutter_modular_test/LICENSE @@ -0,0 +1,201 @@ + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/flutter_modular_test/README.md b/flutter_modular_test/README.md new file mode 100644 index 00000000..410fef9e --- /dev/null +++ b/flutter_modular_test/README.md @@ -0,0 +1,59 @@ +# flutter_modular_test + +Init Modules and test the integration + +## Getting Started + +Add in your pubspec.yaml + +```yaml + +dev_dependecies: + flutter_modular_test: + +``` + +## Using + +### Start a Module + +```dart + +main(){ + setUp(){ + initModule(AppModule()); + } +} + +``` + +### Start more then one Module + +```dart + +main(){ + setUp(){ + initModules([AppModule(), HomeModule(), PerfilModule()]); + } +} + +``` + +### Replace binds of Module + +```dart + +main(){ + + final dioMock = DioMock(); + + setUp(){ + initModule(AppModule(), replaceBinds: [ + Bind.instance(dioMock), + ]); + } +} + +``` + + diff --git a/flutter_modular_test/lib/flutter_modular_test.dart b/flutter_modular_test/lib/flutter_modular_test.dart new file mode 100644 index 00000000..cba2a254 --- /dev/null +++ b/flutter_modular_test/lib/flutter_modular_test.dart @@ -0,0 +1,39 @@ +library flutter_modular_test; + +import 'package:flutter/material.dart'; +import 'package:flutter_modular/flutter_modular.dart'; + +void initModule(ChildModule module, {List> replaceBinds = const [], bool initialModule = false}) { + //Modular.debugMode = false; + final list = module.binds; + for (var item in list) { + var dep = (replaceBinds).firstWhere((dep) { + return item.runtimeType == dep.runtimeType; + }, orElse: () => BindEmpty()); + if (dep is! BindEmpty) { + module.binds.remove(item); + module.binds.add(dep); + } + } + //module.changeBinds(changedList); + if (initialModule) { + Modular.init(module); + } else { + Modular.bindModule(module); + } +} + +void initModules(List modules, {List> replaceBinds = const []}) { + for (var module in modules) { + initModule(module, replaceBinds: replaceBinds); + } +} + +Widget buildTestableWidget(Widget widget) { + return MediaQuery( + data: MediaQueryData(), + child: MaterialApp( + home: widget, + ), + ); +} diff --git a/flutter_modular_test/pubspec.yaml b/flutter_modular_test/pubspec.yaml new file mode 100644 index 00000000..0cee3a00 --- /dev/null +++ b/flutter_modular_test/pubspec.yaml @@ -0,0 +1,57 @@ +name: flutter_modular_test +description: Smart project structure with dependency injection and route management +version: 1.0.0-nullsafety.1 +homepage: https://github.com/Flutterando/modular + +environment: + sdk: ">=2.12.0-0 <3.0.0" + +dependencies: + flutter_modular: ">=3.0.0-nullsafety.18 <4.0.0" + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + +# dependency_overrides: +# flutter_modular: +# path: ../flutter_modular + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/flutter_modular_test/test/flutter_modular_test_test.dart b/flutter_modular_test/test/flutter_modular_test_test.dart new file mode 100644 index 00000000..ae833fe7 --- /dev/null +++ b/flutter_modular_test/test/flutter_modular_test_test.dart @@ -0,0 +1,20 @@ +import 'package:flutter_modular_test/flutter_modular_test.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_modular/flutter_modular.dart'; + +class MyModule extends ChildModule { + final binds = [ + Bind.instance('teste'), + Bind.instance(true), + ]; +} + +void main() { + initModule(MyModule()); + + test('init Module', () { + final text = Modular.get(); + expect(text, 'teste'); + }); +} diff --git a/modular.code-workspace b/modular.code-workspace index 2fb58ed4..c5d87302 100644 --- a/modular.code-workspace +++ b/modular.code-workspace @@ -8,6 +8,9 @@ }, { "path": "flutter_modular_annotations" + }, + { + "path": "flutter_modular_test" } ], "settings": { diff --git a/modular_codegen/lib/src/custom_annotation_generator.dart b/modular_codegen/lib/src/custom_annotation_generator.dart index 005e0092..637469b2 100644 --- a/modular_codegen/lib/src/custom_annotation_generator.dart +++ b/modular_codegen/lib/src/custom_annotation_generator.dart @@ -3,19 +3,16 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:build/build.dart'; import 'package:source_gen/source_gen.dart'; -abstract class CustomGeneratorForAnnotatedField - extends Generator { +abstract class CustomGeneratorForAnnotatedField extends Generator { /// Returns the annotation of type [AnnotationType] of the given [element], /// or [null] if it doesn't have any. - DartObject? getAnnotation(Element element) { - final annotations = - TypeChecker.fromRuntime(AnnotationType).annotationsOf(element); + DartObject getAnnotation(Element element) { + final annotations = TypeChecker.fromRuntime(AnnotationType).annotationsOf(element); if (annotations.isEmpty) { return null; } if (annotations.length > 1) { - throw Exception( - "You tried to add multiple @$AnnotationType() annotations to the " + throw Exception("You tried to add multiple @$AnnotationType() annotations to the " "same element (${element.name}), but that's not possible."); } return annotations.single; @@ -42,6 +39,5 @@ abstract class CustomGeneratorForAnnotatedField return values.join('\n\n'); } - String generateForAnnotatedField( - FieldElement field, ConstantReader annotation); + String generateForAnnotatedField(FieldElement field, ConstantReader annotation); } diff --git a/modular_codegen/lib/src/injection_generator.dart b/modular_codegen/lib/src/injection_generator.dart index e274f8e1..c44cfe06 100644 --- a/modular_codegen/lib/src/injection_generator.dart +++ b/modular_codegen/lib/src/injection_generator.dart @@ -8,8 +8,7 @@ import 'package:source_gen/source_gen.dart'; class InjectionGenerator extends GeneratorForAnnotation { @override - FutureOr generateForAnnotatedElement( - Element element, ConstantReader annotation, BuildStep buildStep) async { + FutureOr generateForAnnotatedElement(Element element, ConstantReader annotation, BuildStep buildStep) async { final singleton = annotation.read('singleton').boolValue; final lazy = annotation.read('lazy').boolValue; @@ -30,14 +29,13 @@ class InjectionGenerator extends GeneratorForAnnotation { break; } } - _write( - "final \$${element.displayName} = BindInject((i) => ${element.displayName}(${visitor.params.join(', ')}), singleton: $singleton, lazy: $lazy,);"); + _write("final \$${element.displayName} = BindInject((i) => ${element.displayName}(${visitor.params.join(', ')}), isSingleton: $singleton, isLazy: $lazy,);"); return _buffer.toString(); } } class ModelVisitor extends SimpleElementVisitor { - DartType? className; + DartType className; List params = []; bool isAnnotation = false; @@ -49,14 +47,12 @@ class ModelVisitor extends SimpleElementVisitor { isAnnotation = element.parameters.firstWhere((param) { if (param.metadata.length > 0) { return param.metadata.firstWhere((param) { - return param.element.displayName == "Data" || - param.element.displayName == "Param" || - param.element.displayName == "Default"; - }, orElse: (() => null!) as ElementAnnotation Function()?) != + return param.element.displayName == "Data" || param.element.displayName == "Param" || param.element.displayName == "Default"; + }, orElse: (() => null) as ElementAnnotation Function()) != null; } return false; - }, orElse: (() => null!) as ParameterElement Function()?) != + }, orElse: (() => null) as ParameterElement Function()) != null; writeParams(element.parameters); } @@ -64,7 +60,7 @@ class ModelVisitor extends SimpleElementVisitor { writeParams(List parameters) { params = parameters.map((param) { if (param.metadata.length > 0) { - String? arg; + String arg; for (var meta in param.metadata) { if (meta.element.displayName == 'Param') { diff --git a/modular_codegen/pubspec.yaml b/modular_codegen/pubspec.yaml index ab0e3379..5e73be5d 100644 --- a/modular_codegen/pubspec.yaml +++ b/modular_codegen/pubspec.yaml @@ -1,23 +1,27 @@ name: modular_codegen description: Code Generate for flutter_modular. Inject Automation. Annotation @Inject, @Param and @Data. -version: 3.0.0-nullsafety.1 +version: 2.1.0 homepage: https://github.com/Flutterando/modular environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" dependencies: flutter_modular_annotations: ^0.0.2 - analyzer: ">=0.38.5 <0.42.0" - glob: ^2.0.0-nullsafety.0 + analyzer: ">=0.38.5 <0.41.0" + glob: ^1.2.0 build: '>=0.12.0 <2.0.0' - build_resolvers: ^1.4.4 - source_gen: ^0.9.10 + build_resolvers: ^1.3.11 + source_gen: ^0.9.6 meta: ">=1.1.8 <2.0.0" flutter: sdk: flutter dev_dependencies: + build_config: ^0.4.2 + build_runner: ">=1.10.0 <2.0.0" + build_test: ^1.2.0 + test: ^1.15.3 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec