- Added Navigator key to dialogs as an optional parameter
- Split dashboard and home routes (in example_nav2) - Removed 'Pages in a router outlet shouldn't participate in the root navigator' restriction
Showing
11 changed files
with
124 additions
and
68 deletions
1 | +import 'dart:async'; | ||
2 | + | ||
3 | +import 'package:get/get.dart'; | ||
4 | + | ||
5 | +class DashboardController extends GetxController { | ||
6 | + final now = DateTime.now().obs; | ||
7 | + @override | ||
8 | + void onReady() { | ||
9 | + super.onReady(); | ||
10 | + Timer.periodic( | ||
11 | + Duration(seconds: 1), | ||
12 | + (timer) { | ||
13 | + now.value = DateTime.now(); | ||
14 | + }, | ||
15 | + ); | ||
16 | + } | ||
17 | +} |
1 | +import 'package:example_nav2/app/modules/dashboard/controllers/dashboard_controller.dart'; | ||
1 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
2 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
3 | 4 | ||
4 | -import '../controllers/home_controller.dart'; | 5 | +import '../../home/controllers/home_controller.dart'; |
5 | 6 | ||
6 | -class DashboardView extends GetView<HomeController> { | 7 | +class DashboardView extends GetView<DashboardController> { |
7 | @override | 8 | @override |
8 | Widget build(BuildContext context) { | 9 | Widget build(BuildContext context) { |
9 | return Scaffold( | 10 | return Scaffold( |
@@ -16,7 +17,7 @@ class DashboardView extends GetView<HomeController> { | @@ -16,7 +17,7 @@ class DashboardView extends GetView<HomeController> { | ||
16 | 'DashboardView is working', | 17 | 'DashboardView is working', |
17 | style: TextStyle(fontSize: 20), | 18 | style: TextStyle(fontSize: 20), |
18 | ), | 19 | ), |
19 | - Text('Time: ${controller.now.value.toString()}') | 20 | + Text('Time: ${controller.now.value.toString()}'), |
20 | ], | 21 | ], |
21 | ), | 22 | ), |
22 | ), | 23 | ), |
@@ -2,16 +2,4 @@ import 'dart:async'; | @@ -2,16 +2,4 @@ import 'dart:async'; | ||
2 | 2 | ||
3 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | 4 | ||
5 | -class HomeController extends GetxController { | ||
6 | - final now = DateTime.now().obs; | ||
7 | - @override | ||
8 | - void onReady() { | ||
9 | - super.onReady(); | ||
10 | - Timer.periodic( | ||
11 | - Duration(seconds: 1), | ||
12 | - (timer) { | ||
13 | - now.value = DateTime.now(); | ||
14 | - }, | ||
15 | - ); | ||
16 | - } | ||
17 | -} | 5 | +class HomeController extends GetxController {} |
@@ -3,7 +3,7 @@ import 'package:get/get.dart'; | @@ -3,7 +3,7 @@ import 'package:get/get.dart'; | ||
3 | 3 | ||
4 | import '../../../routes/app_pages.dart'; | 4 | import '../../../routes/app_pages.dart'; |
5 | import '../controllers/home_controller.dart'; | 5 | import '../controllers/home_controller.dart'; |
6 | -import 'dashboard_view.dart'; | 6 | +import '../../dashboard/views/dashboard_view.dart'; |
7 | 7 | ||
8 | class HomeView extends GetView<HomeController> { | 8 | class HomeView extends GetView<HomeController> { |
9 | @override | 9 | @override |
@@ -22,7 +22,9 @@ class HomeView extends GetView<HomeController> { | @@ -22,7 +22,9 @@ class HomeView extends GetView<HomeController> { | ||
22 | return Scaffold( | 22 | return Scaffold( |
23 | body: GetRouterOutlet( | 23 | body: GetRouterOutlet( |
24 | name: Routes.HOME, | 24 | name: Routes.HOME, |
25 | - emptyWidget: (delegate) => DashboardView(), | 25 | + //It's preferable to use emptyPage instead of emptyWidget |
26 | + emptyPage: (delegate) => | ||
27 | + Get.routeTree.matchRoute(Routes.DASHBOARD).route!, | ||
26 | pickPages: (currentNavStack) { | 28 | pickPages: (currentNavStack) { |
27 | print('Home RouterOutlet: $currentNavStack'); | 29 | print('Home RouterOutlet: $currentNavStack'); |
28 | 30 | ||
@@ -37,7 +39,7 @@ class HomeView extends GetView<HomeController> { | @@ -37,7 +39,7 @@ class HomeView extends GetView<HomeController> { | ||
37 | onTap: (value) { | 39 | onTap: (value) { |
38 | switch (value) { | 40 | switch (value) { |
39 | case 0: | 41 | case 0: |
40 | - delegate.until(Routes.HOME); | 42 | + delegate.toNamed(Routes.HOME); |
41 | break; | 43 | break; |
42 | case 1: | 44 | case 1: |
43 | delegate.toNamed(Routes.PROFILE); | 45 | delegate.toNamed(Routes.PROFILE); |
@@ -12,26 +12,37 @@ class ProductsView extends GetView<ProductsController> { | @@ -12,26 +12,37 @@ class ProductsView extends GetView<ProductsController> { | ||
12 | onPressed: controller.loadDemoProductsFromSomeWhere, | 12 | onPressed: controller.loadDemoProductsFromSomeWhere, |
13 | label: Text('Add'), | 13 | label: Text('Add'), |
14 | ), | 14 | ), |
15 | - body: Obx( | ||
16 | - () => RefreshIndicator( | ||
17 | - onRefresh: () async { | ||
18 | - controller.products.clear(); | ||
19 | - controller.loadDemoProductsFromSomeWhere(); | ||
20 | - }, | ||
21 | - child: ListView.builder( | ||
22 | - itemCount: controller.products.length, | ||
23 | - itemBuilder: (context, index) { | ||
24 | - final item = controller.products[index]; | ||
25 | - return ListTile( | ||
26 | - onTap: () { | ||
27 | - Get.rootDelegate.toNamed(Routes.PRODUCT_DETAILS(item.id)); | 15 | + body: Column( |
16 | + children: [ | ||
17 | + Hero( | ||
18 | + tag: 'heroLogo', | ||
19 | + child: const FlutterLogo(), | ||
20 | + ), | ||
21 | + Expanded( | ||
22 | + child: Obx( | ||
23 | + () => RefreshIndicator( | ||
24 | + onRefresh: () async { | ||
25 | + controller.products.clear(); | ||
26 | + controller.loadDemoProductsFromSomeWhere(); | ||
28 | }, | 27 | }, |
29 | - title: Text(item.name), | ||
30 | - subtitle: Text(item.id), | ||
31 | - ); | ||
32 | - }, | 28 | + child: ListView.builder( |
29 | + itemCount: controller.products.length, | ||
30 | + itemBuilder: (context, index) { | ||
31 | + final item = controller.products[index]; | ||
32 | + return ListTile( | ||
33 | + onTap: () { | ||
34 | + Get.rootDelegate | ||
35 | + .toNamed(Routes.PRODUCT_DETAILS(item.id)); | ||
36 | + }, | ||
37 | + title: Text(item.name), | ||
38 | + subtitle: Text(item.id), | ||
39 | + ); | ||
40 | + }, | ||
41 | + ), | ||
42 | + ), | ||
43 | + ), | ||
33 | ), | 44 | ), |
34 | - ), | 45 | + ], |
35 | ), | 46 | ), |
36 | ); | 47 | ); |
37 | } | 48 | } |
1 | +import 'package:example_nav2/app/routes/app_pages.dart'; | ||
1 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
2 | 3 | ||
3 | import 'package:get/get.dart'; | 4 | import 'package:get/get.dart'; |
@@ -11,11 +12,16 @@ class ProfileView extends GetView<ProfileController> { | @@ -11,11 +12,16 @@ class ProfileView extends GetView<ProfileController> { | ||
11 | backgroundColor: Colors.amber, | 12 | backgroundColor: Colors.amber, |
12 | body: Center( | 13 | body: Center( |
13 | child: Column( | 14 | child: Column( |
15 | + mainAxisSize: MainAxisSize.min, | ||
14 | children: [ | 16 | children: [ |
15 | Text( | 17 | Text( |
16 | 'ProfileView is working', | 18 | 'ProfileView is working', |
17 | style: TextStyle(fontSize: 20), | 19 | style: TextStyle(fontSize: 20), |
18 | ), | 20 | ), |
21 | + Hero( | ||
22 | + tag: 'heroLogo', | ||
23 | + child: const FlutterLogo(), | ||
24 | + ), | ||
19 | MaterialButton( | 25 | MaterialButton( |
20 | child: Text('Show a test dialog'), | 26 | child: Text('Show a test dialog'), |
21 | onPressed: () { | 27 | onPressed: () { |
@@ -25,6 +31,18 @@ class ProfileView extends GetView<ProfileController> { | @@ -25,6 +31,18 @@ class ProfileView extends GetView<ProfileController> { | ||
25 | barrierDismissible: true, | 31 | barrierDismissible: true, |
26 | ); | 32 | ); |
27 | }, | 33 | }, |
34 | + ), | ||
35 | + MaterialButton( | ||
36 | + child: Text('Show a test dialog in Home router outlet'), | ||
37 | + onPressed: () { | ||
38 | + //shows a dialog | ||
39 | + | ||
40 | + Get.defaultDialog( | ||
41 | + title: 'Test Dialog In Home Outlet !!', | ||
42 | + barrierDismissible: true, | ||
43 | + navigatorKey: Get.nestedKey(Routes.HOME), | ||
44 | + ); | ||
45 | + }, | ||
28 | ) | 46 | ) |
29 | ], | 47 | ], |
30 | ), | 48 | ), |
1 | import 'package:get/get.dart'; | 1 | import 'package:get/get.dart'; |
2 | 2 | ||
3 | +import 'package:example_nav2/app/modules/dashboard/bindings/dashboard_binding.dart'; | ||
4 | +import 'package:example_nav2/app/modules/dashboard/views/dashboard_view.dart'; | ||
5 | + | ||
3 | import '../middleware/auth_middleware.dart'; | 6 | import '../middleware/auth_middleware.dart'; |
4 | import '../modules/home/bindings/home_binding.dart'; | 7 | import '../modules/home/bindings/home_binding.dart'; |
5 | import '../modules/home/views/home_view.dart'; | 8 | import '../modules/home/views/home_view.dart'; |
@@ -50,6 +53,11 @@ class AppPages { | @@ -50,6 +53,11 @@ class AppPages { | ||
50 | title: null, | 53 | title: null, |
51 | children: [ | 54 | children: [ |
52 | GetPage( | 55 | GetPage( |
56 | + name: _Paths.DASHBOARD, | ||
57 | + page: () => DashboardView(), | ||
58 | + binding: DashboardBinding(), | ||
59 | + ), | ||
60 | + GetPage( | ||
53 | middlewares: [ | 61 | middlewares: [ |
54 | //only enter this route when authed | 62 | //only enter this route when authed |
55 | EnsureAuthMiddleware(), | 63 | EnsureAuthMiddleware(), |
@@ -14,6 +14,7 @@ abstract class Routes { | @@ -14,6 +14,7 @@ abstract class Routes { | ||
14 | static const LOGIN = _Paths.LOGIN; | 14 | static const LOGIN = _Paths.LOGIN; |
15 | static String LOGIN_THEN(String afterSuccessfulLogin) => | 15 | static String LOGIN_THEN(String afterSuccessfulLogin) => |
16 | '$LOGIN?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}'; | 16 | '$LOGIN?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}'; |
17 | + static const DASHBOARD = _Paths.HOME + _Paths.DASHBOARD; | ||
17 | } | 18 | } |
18 | 19 | ||
19 | abstract class _Paths { | 20 | abstract class _Paths { |
@@ -23,4 +24,5 @@ abstract class _Paths { | @@ -23,4 +24,5 @@ abstract class _Paths { | ||
23 | static const SETTINGS = '/settings'; | 24 | static const SETTINGS = '/settings'; |
24 | static const PRODUCT_DETAILS = '/:productId'; | 25 | static const PRODUCT_DETAILS = '/:productId'; |
25 | static const LOGIN = '/login'; | 26 | static const LOGIN = '/login'; |
27 | + static const DASHBOARD = '/dashboard'; | ||
26 | } | 28 | } |
@@ -215,7 +215,7 @@ extension ExtensionDialog on GetInterface { | @@ -215,7 +215,7 @@ extension ExtensionDialog on GetInterface { | ||
215 | bool barrierDismissible = true, | 215 | bool barrierDismissible = true, |
216 | Color? barrierColor, | 216 | Color? barrierColor, |
217 | bool useSafeArea = true, | 217 | bool useSafeArea = true, |
218 | - bool useRootNavigator = true, | 218 | + GlobalKey<NavigatorState>? navigatorKey, |
219 | Object? arguments, | 219 | Object? arguments, |
220 | Duration? transitionDuration, | 220 | Duration? transitionDuration, |
221 | Curve? transitionCurve, | 221 | Curve? transitionCurve, |
@@ -250,7 +250,7 @@ extension ExtensionDialog on GetInterface { | @@ -250,7 +250,7 @@ extension ExtensionDialog on GetInterface { | ||
250 | child: child, | 250 | child: child, |
251 | ); | 251 | ); |
252 | }, | 252 | }, |
253 | - useRootNavigator: useRootNavigator, | 253 | + navigatorKey: navigatorKey, |
254 | routeSettings: | 254 | routeSettings: |
255 | routeSettings ?? RouteSettings(arguments: arguments, name: name), | 255 | routeSettings ?? RouteSettings(arguments: arguments, name: name), |
256 | ); | 256 | ); |
@@ -264,20 +264,25 @@ extension ExtensionDialog on GetInterface { | @@ -264,20 +264,25 @@ extension ExtensionDialog on GetInterface { | ||
264 | Color barrierColor = const Color(0x80000000), | 264 | Color barrierColor = const Color(0x80000000), |
265 | Duration transitionDuration = const Duration(milliseconds: 200), | 265 | Duration transitionDuration = const Duration(milliseconds: 200), |
266 | RouteTransitionsBuilder? transitionBuilder, | 266 | RouteTransitionsBuilder? transitionBuilder, |
267 | - bool useRootNavigator = true, | 267 | + GlobalKey<NavigatorState>? navigatorKey, |
268 | RouteSettings? routeSettings, | 268 | RouteSettings? routeSettings, |
269 | }) { | 269 | }) { |
270 | assert(!barrierDismissible || barrierLabel != null); | 270 | assert(!barrierDismissible || barrierLabel != null); |
271 | - return Navigator.of(overlayContext!, rootNavigator: useRootNavigator) | ||
272 | - .push<T>(GetDialogRoute<T>( | ||
273 | - pageBuilder: pageBuilder, | ||
274 | - barrierDismissible: barrierDismissible, | ||
275 | - barrierLabel: barrierLabel, | ||
276 | - barrierColor: barrierColor, | ||
277 | - transitionDuration: transitionDuration, | ||
278 | - transitionBuilder: transitionBuilder, | ||
279 | - settings: routeSettings, | ||
280 | - )); | 271 | + final nav = navigatorKey?.currentState ?? |
272 | + Navigator.of(overlayContext!, | ||
273 | + rootNavigator: | ||
274 | + true); //overlay context will always return the root navigator | ||
275 | + return nav.push<T>( | ||
276 | + GetDialogRoute<T>( | ||
277 | + pageBuilder: pageBuilder, | ||
278 | + barrierDismissible: barrierDismissible, | ||
279 | + barrierLabel: barrierLabel, | ||
280 | + barrierColor: barrierColor, | ||
281 | + transitionDuration: transitionDuration, | ||
282 | + transitionBuilder: transitionBuilder, | ||
283 | + settings: routeSettings, | ||
284 | + ), | ||
285 | + ); | ||
281 | } | 286 | } |
282 | 287 | ||
283 | /// Custom UI Dialog. | 288 | /// Custom UI Dialog. |
@@ -309,6 +314,9 @@ extension ExtensionDialog on GetInterface { | @@ -309,6 +314,9 @@ extension ExtensionDialog on GetInterface { | ||
309 | 314 | ||
310 | // onWillPop Scope | 315 | // onWillPop Scope |
311 | WillPopCallback? onWillPop, | 316 | WillPopCallback? onWillPop, |
317 | + | ||
318 | + // the navigator used to push the dialog | ||
319 | + GlobalKey<NavigatorState>? navigatorKey, | ||
312 | }) { | 320 | }) { |
313 | var leanCancel = onCancel != null || textCancel != null; | 321 | var leanCancel = onCancel != null || textCancel != null; |
314 | var leanConfirm = onConfirm != null || textConfirm != null; | 322 | var leanConfirm = onConfirm != null || textConfirm != null; |
@@ -394,19 +402,15 @@ extension ExtensionDialog on GetInterface { | @@ -394,19 +402,15 @@ extension ExtensionDialog on GetInterface { | ||
394 | buttonPadding: EdgeInsets.zero, | 402 | buttonPadding: EdgeInsets.zero, |
395 | ); | 403 | ); |
396 | 404 | ||
397 | - if (onWillPop != null) { | ||
398 | - return dialog<T>( | ||
399 | - WillPopScope( | ||
400 | - onWillPop: onWillPop, | ||
401 | - child: baseAlertDialog, | ||
402 | - ), | ||
403 | - barrierDismissible: barrierDismissible, | ||
404 | - ); | ||
405 | - } | ||
406 | - | ||
407 | return dialog<T>( | 405 | return dialog<T>( |
408 | - baseAlertDialog, | 406 | + onWillPop != null |
407 | + ? WillPopScope( | ||
408 | + onWillPop: onWillPop, | ||
409 | + child: baseAlertDialog, | ||
410 | + ) | ||
411 | + : baseAlertDialog, | ||
409 | barrierDismissible: barrierDismissible, | 412 | barrierDismissible: barrierDismissible, |
413 | + navigatorKey: navigatorKey, | ||
410 | ); | 414 | ); |
411 | } | 415 | } |
412 | } | 416 | } |
@@ -106,13 +106,6 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { | @@ -106,13 +106,6 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { | ||
106 | (pages ?? <GetPage<dynamic>?>[emptyPage?.call(rDelegate)]) | 106 | (pages ?? <GetPage<dynamic>?>[emptyPage?.call(rDelegate)]) |
107 | .whereType<GetPage<dynamic>>() | 107 | .whereType<GetPage<dynamic>>() |
108 | .toList(); | 108 | .toList(); |
109 | - | ||
110 | - final badPages = pageRes.where( | ||
111 | - (element) => element.participatesInRootNavigator == true); | ||
112 | - if (badPages.length > 0) { | ||
113 | - throw """Pages in a router outlet shouldn't participate in the root navigator | ||
114 | - $badPages"""; | ||
115 | - } | ||
116 | if (pageRes.length > 0) { | 109 | if (pageRes.length > 0) { |
117 | return GetNavigator( | 110 | return GetNavigator( |
118 | onPopPage: onPopPage ?? | 111 | onPopPage: onPopPage ?? |
-
Please register or login to post a comment