Ahmed Fwela

minor improvements and bug fixes

1 import 'package:get/get.dart'; 1 import 'package:get/get.dart';
2 2
3 -class LoginController extends GetxController {  
4 - //TODO: Implement LoginController  
5 -  
6 - final count = 0.obs;  
7 - @override  
8 - void onInit() {  
9 - super.onInit();  
10 - }  
11 -  
12 - @override  
13 - void onReady() {  
14 - super.onReady();  
15 - }  
16 -  
17 - @override  
18 - void onClose() {}  
19 - void increment() => count.value++;  
20 -} 3 +class LoginController extends GetxController {}
@@ -33,7 +33,7 @@ class LoginView extends GetView<LoginController> { @@ -33,7 +33,7 @@ class LoginView extends GetView<LoginController> {
33 AuthService.to.login(); 33 AuthService.to.login();
34 final thenTo = Get.rootDelegate.currentConfiguration! 34 final thenTo = Get.rootDelegate.currentConfiguration!
35 .currentPage!.parameter?['then']; 35 .currentPage!.parameter?['then'];
36 - Get.rootDelegate.toNamed(thenTo ?? Routes.HOME); 36 + Get.rootDelegate.offNamed(thenTo ?? Routes.HOME);
37 }, 37 },
38 ), 38 ),
39 ], 39 ],
@@ -4,4 +4,15 @@ class ProductDetailsController extends GetxController { @@ -4,4 +4,15 @@ class ProductDetailsController extends GetxController {
4 final String productId; 4 final String productId;
5 5
6 ProductDetailsController(this.productId); 6 ProductDetailsController(this.productId);
  7 + @override
  8 + void onInit() {
  9 + super.onInit();
  10 + Get.log('ProductDetailsController created with id: $productId');
  11 + }
  12 +
  13 + @override
  14 + void onClose() {
  15 + Get.log('ProductDetailsController close with id: $productId');
  16 + super.onClose();
  17 + }
7 } 18 }
@@ -10,10 +10,24 @@ class ProfileView extends GetView<ProfileController> { @@ -10,10 +10,24 @@ class ProfileView extends GetView<ProfileController> {
10 return Scaffold( 10 return Scaffold(
11 backgroundColor: Colors.amber, 11 backgroundColor: Colors.amber,
12 body: Center( 12 body: Center(
13 - child: Text( 13 + child: Column(
  14 + children: [
  15 + Text(
14 'ProfileView is working', 16 'ProfileView is working',
15 style: TextStyle(fontSize: 20), 17 style: TextStyle(fontSize: 20),
16 ), 18 ),
  19 + MaterialButton(
  20 + child: Text('Show a test dialog'),
  21 + onPressed: () {
  22 + //shows a dialog
  23 + Get.defaultDialog(
  24 + title: 'Test Dialog !!',
  25 + barrierDismissible: true,
  26 + );
  27 + },
  28 + )
  29 + ],
  30 + ),
17 ), 31 ),
18 ); 32 );
19 } 33 }
@@ -18,7 +18,7 @@ class RootView extends GetView<RootController> { @@ -18,7 +18,7 @@ class RootView extends GetView<RootController> {
18 centerTitle: true, 18 centerTitle: true,
19 ), 19 ),
20 body: GetRouterOutlet( 20 body: GetRouterOutlet(
21 - name: '/', 21 + name: 'rootView',
22 emptyPage: (delegate) => 22 emptyPage: (delegate) =>
23 Get.routeTree.matchRoute(Routes.HOME).route!, 23 Get.routeTree.matchRoute(Routes.HOME).route!,
24 pickPages: (currentNavStack) { 24 pickPages: (currentNavStack) {
@@ -31,18 +31,21 @@ class AppPages { @@ -31,18 +31,21 @@ class AppPages {
31 page: () => RootView(), 31 page: () => RootView(),
32 binding: RootBinding(), 32 binding: RootBinding(),
33 participatesInRootNavigator: true, 33 participatesInRootNavigator: true,
  34 + preventDuplicates: true,
34 children: [ 35 children: [
35 GetPage( 36 GetPage(
36 middlewares: [ 37 middlewares: [
37 //only enter this route when not authed 38 //only enter this route when not authed
38 EnsureNotAuthedMiddleware(), 39 EnsureNotAuthedMiddleware(),
39 ], 40 ],
  41 + participatesInRootNavigator: false,
40 name: _Paths.LOGIN, 42 name: _Paths.LOGIN,
41 page: () => LoginView(), 43 page: () => LoginView(),
42 binding: LoginBinding(), 44 binding: LoginBinding(),
43 ), 45 ),
44 GetPage( 46 GetPage(
45 - participatesInRootNavigator: true, 47 + participatesInRootNavigator: false,
  48 + preventDuplicates: true,
46 name: _Paths.HOME, 49 name: _Paths.HOME,
47 page: () => HomeView(), 50 page: () => HomeView(),
48 bindings: [ 51 bindings: [
@@ -16,14 +16,14 @@ void main() { @@ -16,14 +16,14 @@ void main() {
16 }, 16 },
17 ), 17 ),
18 getPages: AppPages.routes, 18 getPages: AppPages.routes,
19 - routeInformationParser: GetInformationParser(  
20 - // initialRoute: Routes.HOME,  
21 - ),  
22 - routerDelegate: GetDelegate(  
23 - backButtonPopMode: PopMode.History,  
24 - preventDuplicateHandlingMode:  
25 - PreventDuplicateHandlingMode.ReorderRoutes,  
26 - ), 19 + // routeInformationParser: GetInformationParser(
  20 + // // initialRoute: Routes.HOME,
  21 + // ),
  22 + // routerDelegate: GetDelegate(
  23 + // backButtonPopMode: PopMode.History,
  24 + // preventDuplicateHandlingMode:
  25 + // PreventDuplicateHandlingMode.ReorderRoutes,
  26 + // ),
27 ), 27 ),
28 ); 28 );
29 } 29 }
@@ -8,6 +8,7 @@ import 'smart_management.dart'; @@ -8,6 +8,7 @@ import 'smart_management.dart';
8 abstract class GetInterface { 8 abstract class GetInterface {
9 SmartManagement smartManagement = SmartManagement.full; 9 SmartManagement smartManagement = SmartManagement.full;
10 RouterDelegate? routerDelegate; 10 RouterDelegate? routerDelegate;
  11 + RouteInformationParser? routeInformationParser;
11 String? reference; 12 String? reference;
12 bool isLogEnable = true; 13 bool isLogEnable = true;
13 LogWriterCallback log = defaultLogWriterCallback; 14 LogWriterCallback log = defaultLogWriterCallback;
@@ -1016,7 +1016,12 @@ you can only use widgets and widget functions here'''; @@ -1016,7 +1016,12 @@ you can only use widgets and widget functions here''';
1016 } 1016 }
1017 1017
1018 GlobalKey<NavigatorState>? nestedKey(dynamic key) { 1018 GlobalKey<NavigatorState>? nestedKey(dynamic key) {
1019 - keys.putIfAbsent(key, () => GlobalKey<NavigatorState>()); 1019 + keys.putIfAbsent(
  1020 + key,
  1021 + () => GlobalKey<NavigatorState>(
  1022 + debugLabel: 'Getx nested key: ${key.toString()}',
  1023 + ),
  1024 + );
1020 return keys[key]; 1025 return keys[key];
1021 } 1026 }
1022 1027
@@ -1207,9 +1212,7 @@ extension NavTwoExt on GetInterface { @@ -1207,9 +1212,7 @@ extension NavTwoExt on GetInterface {
1207 1212
1208 /// Casts the stored router delegate to a desired type 1213 /// Casts the stored router delegate to a desired type
1209 TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() => 1214 TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>
1210 - _routerDelegate as TDelegate?;  
1211 -  
1212 - static GetDelegate? _routerDelegate; 1215 + routerDelegate as TDelegate?;
1213 1216
1214 // // ignore: use_setters_to_change_properties 1217 // // ignore: use_setters_to_change_properties
1215 // void setDefaultDelegate(RouterDelegate? delegate) { 1218 // void setDefaultDelegate(RouterDelegate? delegate) {
@@ -1218,31 +1221,39 @@ extension NavTwoExt on GetInterface { @@ -1218,31 +1221,39 @@ extension NavTwoExt on GetInterface {
1218 1221
1219 // GetDelegate? getDelegate() => delegate<GetDelegate, GetNavConfig>(); 1222 // GetDelegate? getDelegate() => delegate<GetDelegate, GetNavConfig>();
1220 1223
1221 - static GetInformationParser? _informationParser;  
1222 -  
1223 GetInformationParser createInformationParser({String initialRoute = '/'}) { 1224 GetInformationParser createInformationParser({String initialRoute = '/'}) {
1224 - return _informationParser ??=  
1225 - GetInformationParser(initialRoute: initialRoute); 1225 + if (routeInformationParser == null) {
  1226 + return routeInformationParser = GetInformationParser(
  1227 + initialRoute: initialRoute,
  1228 + );
  1229 + } else {
  1230 + return routerDelegate as GetInformationParser;
  1231 + }
1226 } 1232 }
1227 1233
1228 // static GetDelegate? _delegate; 1234 // static GetDelegate? _delegate;
1229 1235
1230 GetDelegate get rootDelegate => createDelegate(); 1236 GetDelegate get rootDelegate => createDelegate();
1231 1237
1232 - GetDelegate createDelegate(  
1233 - {GetPage<dynamic>? notFoundRoute, 1238 + GetDelegate createDelegate({
  1239 + GetPage<dynamic>? notFoundRoute,
1234 List<NavigatorObserver>? navigatorObservers, 1240 List<NavigatorObserver>? navigatorObservers,
1235 TransitionDelegate<dynamic>? transitionDelegate, 1241 TransitionDelegate<dynamic>? transitionDelegate,
1236 PopMode backButtonPopMode = PopMode.History, 1242 PopMode backButtonPopMode = PopMode.History,
1237 PreventDuplicateHandlingMode preventDuplicateHandlingMode = 1243 PreventDuplicateHandlingMode preventDuplicateHandlingMode =
1238 - PreventDuplicateHandlingMode.ReorderRoutes}) {  
1239 - return _routerDelegate ??= GetDelegate( 1244 + PreventDuplicateHandlingMode.ReorderRoutes,
  1245 + }) {
  1246 + if (routerDelegate == null) {
  1247 + return routerDelegate = GetDelegate(
1240 notFoundRoute: notFoundRoute, 1248 notFoundRoute: notFoundRoute,
1241 navigatorObservers: navigatorObservers, 1249 navigatorObservers: navigatorObservers,
1242 transitionDelegate: transitionDelegate, 1250 transitionDelegate: transitionDelegate,
1243 backButtonPopMode: backButtonPopMode, 1251 backButtonPopMode: backButtonPopMode,
1244 preventDuplicateHandlingMode: preventDuplicateHandlingMode, 1252 preventDuplicateHandlingMode: preventDuplicateHandlingMode,
1245 ); 1253 );
  1254 + } else {
  1255 + return routerDelegate as GetDelegate;
  1256 + }
1246 } 1257 }
1247 } 1258 }
1248 1259
@@ -7,7 +7,9 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { @@ -7,7 +7,9 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> {
7 7
8 GetInformationParser({ 8 GetInformationParser({
9 this.initialRoute = '/', 9 this.initialRoute = '/',
10 - }); 10 + }) {
  11 + Get.log('GetInformationParser is created !');
  12 + }
11 @override 13 @override
12 SynchronousFuture<GetNavConfig> parseRouteInformation( 14 SynchronousFuture<GetNavConfig> parseRouteInformation(
13 RouteInformation routeInformation, 15 RouteInformation routeInformation,
@@ -46,7 +46,7 @@ enum PreventDuplicateHandlingMode { @@ -46,7 +46,7 @@ enum PreventDuplicateHandlingMode {
46 ReorderRoutes 46 ReorderRoutes
47 } 47 }
48 48
49 -class GetDelegate<T> extends RouterDelegate<GetNavConfig> 49 +class GetDelegate extends RouterDelegate<GetNavConfig>
50 with ListenableMixin, ListNotifierMixin { 50 with ListenableMixin, ListNotifierMixin {
51 final List<GetNavConfig> history = <GetNavConfig>[]; 51 final List<GetNavConfig> history = <GetNavConfig>[];
52 final PopMode backButtonPopMode; 52 final PopMode backButtonPopMode;
@@ -68,7 +68,9 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig> @@ -68,7 +68,9 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig>
68 this.backButtonPopMode = PopMode.History, 68 this.backButtonPopMode = PopMode.History,
69 this.preventDuplicateHandlingMode = 69 this.preventDuplicateHandlingMode =
70 PreventDuplicateHandlingMode.ReorderRoutes, 70 PreventDuplicateHandlingMode.ReorderRoutes,
71 - }); 71 + }) {
  72 + Get.log('GetDelegate is created !');
  73 + }
72 74
73 GetNavConfig? runMiddleware(GetNavConfig config) { 75 GetNavConfig? runMiddleware(GetNavConfig config) {
74 final middlewares = config.currentTreeBranch.last.middlewares ?? []; 76 final middlewares = config.currentTreeBranch.last.middlewares ?? [];
@@ -93,7 +95,7 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig> @@ -93,7 +95,7 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig>
93 } 95 }
94 96
95 GetNavConfig? _unsafeHistoryRemoveAt(int index) { 97 GetNavConfig? _unsafeHistoryRemoveAt(int index) {
96 - if (index == history.length - 1) { 98 + if (index == history.length - 1 && history.length > 1) {
97 //removing WILL update the current route 99 //removing WILL update the current route
98 final toCheck = history[history.length - 2]; 100 final toCheck = history[history.length - 2];
99 final resMiddleware = runMiddleware(toCheck); 101 final resMiddleware = runMiddleware(toCheck);
@@ -290,8 +292,9 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig> @@ -290,8 +292,9 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig>
290 292
291 @override 293 @override
292 Future<void> setInitialRoutePath(GetNavConfig configuration) async { 294 Future<void> setInitialRoutePath(GetNavConfig configuration) async {
293 - _unsafeHistoryClear();  
294 - _resultCompleter.clear(); 295 + //no need to clear history with Reorder route strategy
  296 + // _unsafeHistoryClear();
  297 + // _resultCompleter.clear();
295 await pushHistory(configuration); 298 await pushHistory(configuration);
296 } 299 }
297 300
@@ -318,6 +321,11 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig> @@ -318,6 +321,11 @@ class GetDelegate<T> extends RouterDelegate<GetNavConfig>
318 ); 321 );
319 } 322 }
320 323
  324 + Future<T?> offNamed<T>(String fullRoute) async {
  325 + await popHistory();
  326 + return await toNamed(fullRoute);
  327 + }
  328 +
321 /// Removes routes according to [PopMode] 329 /// Removes routes according to [PopMode]
322 /// until it reaches the specifc [fullRoute], 330 /// until it reaches the specifc [fullRoute],
323 /// DOES NOT remove the [fullRoute] 331 /// DOES NOT remove the [fullRoute]
@@ -25,17 +25,17 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object> @@ -25,17 +25,17 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
25 required Widget Function( 25 required Widget Function(
26 BuildContext context, 26 BuildContext context,
27 TDelegate, 27 TDelegate,
28 - GetPage? page, 28 + List<GetPage>? page,
29 ) 29 )
30 pageBuilder, 30 pageBuilder,
31 }) : this.builder( 31 }) : this.builder(
32 builder: (context, rDelegate, currentConfig) { 32 builder: (context, rDelegate, currentConfig) {
33 - final picked =  
34 - currentConfig == null ? <GetPage>[] : pickPages(currentConfig);  
35 - if (picked.length == 0) {  
36 - return pageBuilder(context, rDelegate, null); 33 + var picked =
  34 + currentConfig == null ? null : pickPages(currentConfig);
  35 + if (picked?.length == 0) {
  36 + picked = null;
37 } 37 }
38 - return pageBuilder(context, rDelegate, picked.last); 38 + return pageBuilder(context, rDelegate, picked);
39 }, 39 },
40 delegate: delegate, 40 delegate: delegate,
41 ); 41 );
@@ -101,15 +101,25 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { @@ -101,15 +101,25 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> {
101 (emptyPage == null && emptyWidget != null), 101 (emptyPage == null && emptyWidget != null),
102 'Either use emptyPage or emptyWidget'), 102 'Either use emptyPage or emptyWidget'),
103 super( 103 super(
104 - pageBuilder: (context, rDelegate, page) {  
105 - var pageRes = page ?? emptyPage?.call(rDelegate);  
106 - if (pageRes != null) { 104 + pageBuilder: (context, rDelegate, pages) {
  105 + final pageRes =
  106 + (pages ?? <GetPage<dynamic>?>[emptyPage?.call(rDelegate)])
  107 + .whereType<GetPage<dynamic>>()
  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) {
107 return GetNavigator( 117 return GetNavigator(
108 onPopPage: onPopPage ?? 118 onPopPage: onPopPage ??
109 (a, c) { 119 (a, c) {
110 return true; 120 return true;
111 }, 121 },
112 - pages: [pageRes], 122 + pages: pageRes,
113 name: name, 123 name: name,
114 ); 124 );
115 } 125 }
@@ -163,9 +163,11 @@ class GetCupertinoApp extends StatelessWidget { @@ -163,9 +163,11 @@ class GetCupertinoApp extends StatelessWidget {
163 this.defaultGlobalState, 163 this.defaultGlobalState,
164 this.getPages, 164 this.getPages,
165 this.unknownRoute, 165 this.unknownRoute,
166 - }) : routerDelegate = routerDelegate ?? Get.createDelegate(),  
167 - routeInformationParser = routeInformationParser ??  
168 - Get.createInformationParser( 166 + }) : routerDelegate = routerDelegate ??= Get.createDelegate(
  167 + notFoundRoute: unknownRoute,
  168 + ),
  169 + routeInformationParser =
  170 + routeInformationParser ??= Get.createInformationParser(
169 initialRoute: getPages?.first.name ?? '/', 171 initialRoute: getPages?.first.name ?? '/',
170 ), 172 ),
171 navigatorObservers = null, 173 navigatorObservers = null,
@@ -176,7 +178,10 @@ class GetCupertinoApp extends StatelessWidget { @@ -176,7 +178,10 @@ class GetCupertinoApp extends StatelessWidget {
176 onUnknownRoute = null, 178 onUnknownRoute = null,
177 routes = null, 179 routes = null,
178 initialRoute = null, 180 initialRoute = null,
179 - super(key: key); 181 + super(key: key) {
  182 + Get.routerDelegate = routerDelegate;
  183 + Get.routeInformationParser = routeInformationParser;
  184 + }
180 185
181 Route<dynamic> generator(RouteSettings settings) { 186 Route<dynamic> generator(RouteSettings settings) {
182 return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); 187 return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
@@ -173,9 +173,11 @@ class GetMaterialApp extends StatelessWidget { @@ -173,9 +173,11 @@ class GetMaterialApp extends StatelessWidget {
173 this.defaultGlobalState, 173 this.defaultGlobalState,
174 this.getPages, 174 this.getPages,
175 this.unknownRoute, 175 this.unknownRoute,
176 - }) : routerDelegate = routerDelegate ?? Get.createDelegate(),  
177 - routeInformationParser = routeInformationParser ??  
178 - Get.createInformationParser( 176 + }) : routerDelegate = routerDelegate ??= Get.createDelegate(
  177 + notFoundRoute: unknownRoute,
  178 + ),
  179 + routeInformationParser =
  180 + routeInformationParser ??= Get.createInformationParser(
179 initialRoute: getPages?.first.name ?? '/', 181 initialRoute: getPages?.first.name ?? '/',
180 ), 182 ),
181 navigatorObservers = null, 183 navigatorObservers = null,
@@ -186,7 +188,10 @@ class GetMaterialApp extends StatelessWidget { @@ -186,7 +188,10 @@ class GetMaterialApp extends StatelessWidget {
186 onUnknownRoute = null, 188 onUnknownRoute = null,
187 routes = null, 189 routes = null,
188 initialRoute = null, 190 initialRoute = null,
189 - super(key: key); 191 + super(key: key) {
  192 + Get.routerDelegate = routerDelegate;
  193 + Get.routeInformationParser = routeInformationParser;
  194 + }
190 195
191 Route<dynamic> generator(RouteSettings settings) { 196 Route<dynamic> generator(RouteSettings settings) {
192 return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); 197 return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
@@ -128,24 +128,9 @@ class ParseRouteTree { @@ -128,24 +128,9 @@ class ParseRouteTree {
128 /// Change the Path for a [GetPage] 128 /// Change the Path for a [GetPage]
129 GetPage _addChild( 129 GetPage _addChild(
130 GetPage origin, String parentPath, List<GetMiddleware> middlewares) => 130 GetPage origin, String parentPath, List<GetMiddleware> middlewares) =>
131 - GetPage(  
132 - name: (parentPath + origin.name).replaceAll(r'//', '/'),  
133 - page: origin.page,  
134 - title: origin.title,  
135 - alignment: origin.alignment,  
136 - transition: origin.transition,  
137 - binding: origin.binding,  
138 - bindings: origin.bindings,  
139 - curve: origin.curve,  
140 - customTransition: origin.customTransition,  
141 - fullscreenDialog: origin.fullscreenDialog,  
142 - maintainState: origin.maintainState,  
143 - opaque: origin.opaque,  
144 - parameter: origin.parameter,  
145 - popGesture: origin.popGesture,  
146 - preventDuplicates: origin.preventDuplicates,  
147 - transitionDuration: origin.transitionDuration, 131 + origin.copy(
148 middlewares: middlewares, 132 middlewares: middlewares,
  133 + name: (parentPath + origin.name).replaceAll(r'//', '/'),
149 ); 134 );
150 135
151 GetPage? _findRoute(String name) { 136 GetPage? _findRoute(String name) {
@@ -29,7 +29,7 @@ class GetMaterialController extends GetxController { @@ -29,7 +29,7 @@ class GetMaterialController extends GetxController {
29 29
30 CustomTransition? customTransition; 30 CustomTransition? customTransition;
31 31
32 - GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>(); 32 + var key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default');
33 33
34 Map<dynamic, GlobalKey<NavigatorState>> keys = {}; 34 Map<dynamic, GlobalKey<NavigatorState>> keys = {};
35 35