Jonny Borges

revert b1b8c9eb

@@ -7,7 +7,7 @@ import 'routes/app_pages.dart'; @@ -7,7 +7,7 @@ import 'routes/app_pages.dart';
7 import 'shared/logger/logger_utils.dart'; 7 import 'shared/logger/logger_utils.dart';
8 8
9 void main() { 9 void main() {
10 - runApp(MyApp()); 10 + runApp(const MyApp());
11 } 11 }
12 12
13 class MyApp extends StatelessWidget { 13 class MyApp extends StatelessWidget {
1 import 'package:flutter/foundation.dart'; 1 import 'package:flutter/foundation.dart';
2 import 'package:flutter/widgets.dart'; 2 import 'package:flutter/widgets.dart';
  3 +
3 import '../../../get.dart'; 4 import '../../../get.dart';
4 5
5 class GetInformationParser extends RouteInformationParser<GetNavConfig> { 6 class GetInformationParser extends RouteInformationParser<GetNavConfig> {
@@ -14,7 +15,6 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { @@ -14,7 +15,6 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> {
14 SynchronousFuture<GetNavConfig> parseRouteInformation( 15 SynchronousFuture<GetNavConfig> parseRouteInformation(
15 RouteInformation routeInformation, 16 RouteInformation routeInformation,
16 ) { 17 ) {
17 - Get.log('GetInformationParser: route location: ${routeInformation.location}');  
18 var location = routeInformation.location; 18 var location = routeInformation.location;
19 if (location == '/') { 19 if (location == '/') {
20 //check if there is a corresponding page 20 //check if there is a corresponding page
@@ -24,6 +24,8 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { @@ -24,6 +24,8 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> {
24 } 24 }
25 } 25 }
26 26
  27 + Get.log('GetInformationParser: route location: $location');
  28 +
27 final matchResult = Get.routeTree.matchRoute(location ?? initialRoute); 29 final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
28 30
29 return SynchronousFuture( 31 return SynchronousFuture(
@@ -2,50 +2,10 @@ import 'dart:async'; @@ -2,50 +2,10 @@ import 'dart:async';
2 2
3 import 'package:flutter/foundation.dart'; 3 import 'package:flutter/foundation.dart';
4 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
  5 +
5 import '../../../get.dart'; 6 import '../../../get.dart';
6 import '../../../get_state_manager/src/simple/list_notifier.dart'; 7 import '../../../get_state_manager/src/simple/list_notifier.dart';
7 8
8 -/// Enables the user to customize the intended pop behavior  
9 -///  
10 -/// Goes to either the previous history entry or the previous page entry  
11 -///  
12 -/// e.g. if the user navigates to these pages  
13 -/// 1) /home  
14 -/// 2) /home/products/1234  
15 -///  
16 -/// when popping on [History] mode, it will emulate a browser back button.  
17 -///  
18 -/// so the new history stack will be:  
19 -/// 1) /home  
20 -///  
21 -/// when popping on [Page] mode, it will only remove the last part of the route  
22 -/// so the new history stack will be:  
23 -/// 1) /home  
24 -/// 2) /home/products  
25 -///  
26 -/// another pop will change the history stack to:  
27 -/// 1) /home  
28 -enum PopMode {  
29 - History,  
30 - Page,  
31 -}  
32 -  
33 -/// Enables the user to customize the behavior when pushing multiple routes that  
34 -/// shouldn't be duplicates  
35 -enum PreventDuplicateHandlingMode {  
36 - /// Removes the history entries until it reaches the old route  
37 - PopUntilOriginalRoute,  
38 -  
39 - /// Simply don't push the new route  
40 - DoNothing,  
41 -  
42 - /// Recommended - Moves the old route entry to the front  
43 - ///  
44 - /// With this mode, you guarantee there will be only one  
45 - /// route entry for each location  
46 - ReorderRoutes  
47 -}  
48 -  
49 class GetDelegate extends RouterDelegate<GetNavConfig> 9 class GetDelegate extends RouterDelegate<GetNavConfig>
50 with ListenableMixin, ListNotifierMixin { 10 with ListenableMixin, ListNotifierMixin {
51 final List<GetNavConfig> history = <GetNavConfig>[]; 11 final List<GetNavConfig> history = <GetNavConfig>[];
@@ -57,7 +17,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -57,7 +17,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
57 final List<NavigatorObserver>? navigatorObservers; 17 final List<NavigatorObserver>? navigatorObservers;
58 final TransitionDelegate<dynamic>? transitionDelegate; 18 final TransitionDelegate<dynamic>? transitionDelegate;
59 19
60 - GlobalKey<NavigatorState> get navigatorKey => Get.key; 20 + final _allCompleters = <GetPage, Completer>{};
61 21
62 GetDelegate({ 22 GetDelegate({
63 GetPage? notFoundRoute, 23 GetPage? notFoundRoute,
@@ -76,191 +36,72 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -76,191 +36,72 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
76 Get.log('GetDelegate is created !'); 36 Get.log('GetDelegate is created !');
77 } 37 }
78 38
79 - Future<GetNavConfig?> runMiddleware(GetNavConfig config) async {  
80 - final middlewares = config.currentTreeBranch.last.middlewares;  
81 - if (middlewares == null) {  
82 - return config;  
83 - }  
84 - var iterator = config;  
85 - for (var item in middlewares) {  
86 - var redirectRes = await item.redirectDelegate(iterator);  
87 - if (redirectRes == null) return null;  
88 - iterator = redirectRes;  
89 - }  
90 - return iterator;  
91 - }  
92 -  
93 - Future<void> _unsafeHistoryAdd(GetNavConfig config) async {  
94 - final res = await runMiddleware(config);  
95 - if (res == null) return;  
96 - history.add(res); 39 + @override
  40 + GetNavConfig? get currentConfiguration {
  41 + if (history.isEmpty) return null;
  42 + final route = history.last;
  43 + return route;
97 } 44 }
98 45
99 - Future<void> _unsafeHistoryRemove(GetNavConfig config) async {  
100 - var index = history.indexOf(config);  
101 - if (index >= 0) await _unsafeHistoryRemoveAt(index);  
102 - } 46 + GlobalKey<NavigatorState> get navigatorKey => Get.key;
103 47
104 - Future<GetNavConfig?> _unsafeHistoryRemoveAt(int index) async {  
105 - if (index == history.length - 1 && history.length > 1) {  
106 - //removing WILL update the current route  
107 - final toCheck = history[history.length - 2];  
108 - final resMiddleware = await runMiddleware(toCheck);  
109 - if (resMiddleware == null) return null;  
110 - history[history.length - 2] = resMiddleware;  
111 - }  
112 - return history.removeAt(index); 48 + Map<String, String> get parameters {
  49 + return currentConfiguration?.currentPage?.parameters ?? {};
113 } 50 }
114 51
115 T arguments<T>() { 52 T arguments<T>() {
116 return currentConfiguration?.currentPage?.arguments as T; 53 return currentConfiguration?.currentPage?.arguments as T;
117 } 54 }
118 55
119 - Map<String, String> get parameters {  
120 - return currentConfiguration?.currentPage?.parameters ?? {};  
121 - }  
122 -  
123 - // void _unsafeHistoryClear() {  
124 - // history.clear();  
125 - // }  
126 -  
127 - /// Adds a new history entry and waits for the result  
128 - Future<void> pushHistory(  
129 - GetNavConfig config, {  
130 - bool rebuildStack = true, 56 + /// Removes routes according to [PopMode]
  57 + /// until it reaches the specifc [fullRoute],
  58 + /// DOES NOT remove the [fullRoute]
  59 + Future<void> backUntil(
  60 + String fullRoute, {
  61 + PopMode popMode = PopMode.Page,
131 }) async { 62 }) async {
132 - //this changes the currentConfiguration  
133 - await _pushHistory(config);  
134 - if (rebuildStack) {  
135 - refresh(); 63 + // remove history or page entries until you meet route
  64 + var iterator = currentConfiguration;
  65 + while (_canPop(popMode) &&
  66 + iterator != null &&
  67 + iterator.location != fullRoute) {
  68 + await _pop(popMode);
  69 + // replace iterator
  70 + iterator = currentConfiguration;
136 } 71 }
  72 + refresh();
137 } 73 }
138 74
139 - Future<void> _removeHistoryEntry(GetNavConfig entry) async {  
140 - await _unsafeHistoryRemove(entry);  
141 - }  
142 -  
143 - Future<void> _pushHistory(GetNavConfig config) async {  
144 - if (config.currentPage!.preventDuplicates) {  
145 - final originalEntryIndex =  
146 - history.indexWhere((element) => element.location == config.location);  
147 - if (originalEntryIndex >= 0) {  
148 - switch (preventDuplicateHandlingMode) {  
149 - case PreventDuplicateHandlingMode.PopUntilOriginalRoute:  
150 - await backUntil(config.location!, popMode: PopMode.Page);  
151 - break;  
152 - case PreventDuplicateHandlingMode.ReorderRoutes:  
153 - await _unsafeHistoryRemoveAt(originalEntryIndex);  
154 - await _unsafeHistoryAdd(config);  
155 - break;  
156 - case PreventDuplicateHandlingMode.DoNothing:  
157 - default:  
158 - break;  
159 - }  
160 - return;  
161 - }  
162 - }  
163 - await _unsafeHistoryAdd(config); 75 + @override
  76 + Widget build(BuildContext context) {
  77 + final pages = getVisualPages();
  78 + if (pages.length == 0) return SizedBox.shrink();
  79 + final extraObservers = navigatorObservers;
  80 + return GetNavigator(
  81 + key: navigatorKey,
  82 + onPopPage: _onPopVisualRoute,
  83 + pages: pages,
  84 + observers: [
  85 + GetObserver(),
  86 + if (extraObservers != null) ...extraObservers,
  87 + ],
  88 + transitionDelegate:
  89 + transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
  90 + );
164 } 91 }
165 92
166 - // GetPageRoute getPageRoute(RouteSettings? settings) {  
167 - // return PageRedirect(settings ?? RouteSettings(name: '/404'), _notFound())  
168 - // .page(); 93 + // void _unsafeHistoryClear() {
  94 + // history.clear();
169 // } 95 // }
170 96
171 - Future<GetNavConfig?> _popHistory() async {  
172 - if (!_canPopHistory()) return null;  
173 - return await _doPopHistory();  
174 - }  
175 -  
176 - Future<GetNavConfig?> _doPopHistory() async {  
177 - return await _unsafeHistoryRemoveAt(history.length - 1);  
178 - }  
179 -  
180 - Future<GetNavConfig?> _popPage() async {  
181 - if (!_canPopPage()) return null;  
182 - return await _doPopPage();  
183 - }  
184 -  
185 - Future<GetNavConfig?> _pop(PopMode mode) async {  
186 - switch (mode) {  
187 - case PopMode.History:  
188 - return await _popHistory();  
189 - case PopMode.Page:  
190 - return await _popPage();  
191 - default:  
192 - return null;  
193 - }  
194 - }  
195 -  
196 - // returns the popped page  
197 - Future<GetNavConfig?> _doPopPage() async {  
198 - final currentBranch = currentConfiguration?.currentTreeBranch;  
199 - if (currentBranch != null && currentBranch.length > 1) {  
200 - //remove last part only  
201 - final remaining = currentBranch.take(currentBranch.length - 1);  
202 - final prevHistoryEntry =  
203 - history.length > 1 ? history[history.length - 2] : null;  
204 -  
205 - //check if current route is the same as the previous route  
206 - if (prevHistoryEntry != null) {  
207 - //if so, pop the entire history entry  
208 - final newLocation = remaining.last.name;  
209 - final prevLocation = prevHistoryEntry.location;  
210 - if (newLocation == prevLocation) {  
211 - //pop the entire history entry  
212 - return await _popHistory();  
213 - }  
214 - }  
215 -  
216 - //create a new route with the remaining tree branch  
217 - final res = await _popHistory();  
218 - await _pushHistory(  
219 - GetNavConfig(  
220 - currentTreeBranch: remaining.toList(),  
221 - location: remaining.last.name,  
222 - state: null, //TOOD: persist state??  
223 - ),  
224 - );  
225 - return res;  
226 - } else {  
227 - //remove entire entry  
228 - return await _popHistory();  
229 - }  
230 - }  
231 -  
232 - Future<GetNavConfig?> popHistory() async {  
233 - return await _popHistory();  
234 - }  
235 -  
236 - bool _canPopHistory() {  
237 - return history.length > 1;  
238 - }  
239 -  
240 Future<bool> canPopHistory() { 97 Future<bool> canPopHistory() {
241 return SynchronousFuture(_canPopHistory()); 98 return SynchronousFuture(_canPopHistory());
242 } 99 }
243 100
244 - bool _canPopPage() {  
245 - final currentTreeBranch = currentConfiguration?.currentTreeBranch;  
246 - if (currentTreeBranch == null) return false;  
247 - return currentTreeBranch.length > 1 ? true : _canPopHistory();  
248 - }  
249 -  
250 Future<bool> canPopPage() { 101 Future<bool> canPopPage() {
251 return SynchronousFuture(_canPopPage()); 102 return SynchronousFuture(_canPopPage());
252 } 103 }
253 104
254 - bool _canPop(PopMode mode) {  
255 - switch (mode) {  
256 - case PopMode.History:  
257 - return _canPopHistory();  
258 - case PopMode.Page:  
259 - default:  
260 - return _canPopPage();  
261 - }  
262 - }  
263 -  
264 /// gets the visual pages from the current history entry 105 /// gets the visual pages from the current history entry
265 /// 106 ///
266 /// visual pages must have [participatesInRootNavigator] set to true 107 /// visual pages must have [participatesInRootNavigator] set to true
@@ -281,44 +122,104 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -281,44 +122,104 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
281 } 122 }
282 } 123 }
283 124
  125 + // GetPageRoute getPageRoute(RouteSettings? settings) {
  126 + // return PageRedirect(settings ?? RouteSettings(name: '/404'), _notFound())
  127 + // .page();
  128 + // }
  129 +
  130 + Future<bool> handlePopupRoutes({
  131 + Object? result,
  132 + }) async {
  133 + Route? currentRoute;
  134 + navigatorKey.currentState!.popUntil((route) {
  135 + currentRoute = route;
  136 + return true;
  137 + });
  138 + if (currentRoute is PopupRoute) {
  139 + return await navigatorKey.currentState!.maybePop(result);
  140 + }
  141 + return false;
  142 + }
  143 +
  144 + Future<T?>? offAndToNamed<T>(
  145 + String page, {
  146 + dynamic arguments,
  147 + int? id,
  148 + dynamic result,
  149 + Map<String, String>? parameters,
  150 + PopMode popMode = PopMode.History,
  151 + }) async {
  152 + if (parameters != null) {
  153 + final uri = Uri(path: page, queryParameters: parameters);
  154 + page = uri.toString();
  155 + }
  156 +
  157 + await popRoute(result: result);
  158 + return toNamed(page, arguments: arguments, parameters: parameters);
  159 + }
  160 +
  161 + Future<T> offNamed<T>(
  162 + String page, {
  163 + dynamic arguments,
  164 + Map<String, String>? parameters,
  165 + }) async {
  166 + history.removeLast();
  167 + return toNamed<T>(page, arguments: arguments, parameters: parameters);
  168 + }
  169 +
  170 + Future<GetNavConfig?> popHistory() async {
  171 + return await _popHistory();
  172 + }
  173 +
  174 + // returns the popped page
284 @override 175 @override
285 - Widget build(BuildContext context) {  
286 - final pages = getVisualPages();  
287 - if (pages.length == 0) return SizedBox.shrink();  
288 - final extraObservers = navigatorObservers;  
289 - return GetNavigator(  
290 - key: navigatorKey,  
291 - onPopPage: _onPopVisualRoute,  
292 - pages: pages,  
293 - observers: [  
294 - GetObserver(),  
295 - if (extraObservers != null) ...extraObservers,  
296 - ],  
297 - transitionDelegate:  
298 - transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),  
299 - ); 176 + Future<bool> popRoute({
  177 + Object? result,
  178 + PopMode popMode = PopMode.Page,
  179 + }) async {
  180 + //Returning false will cause the entire app to be popped.
  181 + final wasPopup = await handlePopupRoutes(result: result);
  182 + if (wasPopup) return true;
  183 + final _popped = await _pop(popMode);
  184 + refresh();
  185 + if (_popped != null) {
  186 + //emulate the old pop with result
  187 + return true;
  188 + }
  189 + return false;
  190 + }
  191 +
  192 + /// Adds a new history entry and waits for the result
  193 + Future<void> pushHistory(
  194 + GetNavConfig config, {
  195 + bool rebuildStack = true,
  196 + }) async {
  197 + //this changes the currentConfiguration
  198 + await _pushHistory(config);
  199 + if (rebuildStack) {
  200 + refresh();
  201 + }
  202 + }
  203 +
  204 + Future<GetNavConfig?> runMiddleware(GetNavConfig config) async {
  205 + final middlewares = config.currentTreeBranch.last.middlewares;
  206 + if (middlewares == null) {
  207 + return config;
  208 + }
  209 + var iterator = config;
  210 + for (var item in middlewares) {
  211 + var redirectRes = await item.redirectDelegate(iterator);
  212 + if (redirectRes == null) return null;
  213 + iterator = redirectRes;
  214 + }
  215 + return iterator;
300 } 216 }
301 217
302 - // @override  
303 - // Future<void> setInitialRoutePath(GetNavConfig configuration) async {  
304 - // //no need to clear history with Reorder route strategy  
305 - // // _unsafeHistoryClear();  
306 - // // _resultCompleter.clear();  
307 - // await pushHistory(configuration);  
308 - // }  
309 -  
310 @override 218 @override
311 Future<void> setNewRoutePath(GetNavConfig configuration) async { 219 Future<void> setNewRoutePath(GetNavConfig configuration) async {
312 await pushHistory(configuration); 220 await pushHistory(configuration);
313 } 221 }
314 222
315 - @override  
316 - GetNavConfig? get currentConfiguration {  
317 - if (history.isEmpty) return null;  
318 - final route = history.last;  
319 - return route;  
320 - }  
321 -  
322 Future<T> toNamed<T>( 223 Future<T> toNamed<T>(
323 String page, { 224 String page, {
324 dynamic arguments, 225 dynamic arguments,
@@ -352,84 +253,73 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -352,84 +253,73 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
352 } 253 }
353 } 254 }
354 255
355 - Future<T?>? offAndToNamed<T>(  
356 - String page, {  
357 - dynamic arguments,  
358 - int? id,  
359 - dynamic result,  
360 - Map<String, String>? parameters,  
361 - PopMode popMode = PopMode.History,  
362 - }) async {  
363 - if (parameters != null) {  
364 - final uri = Uri(path: page, queryParameters: parameters);  
365 - page = uri.toString(); 256 + bool _canPop(PopMode mode) {
  257 + switch (mode) {
  258 + case PopMode.History:
  259 + return _canPopHistory();
  260 + case PopMode.Page:
  261 + default:
  262 + return _canPopPage();
366 } 263 }
367 -  
368 - await popRoute(result: result);  
369 - return toNamed(page, arguments: arguments, parameters: parameters);  
370 } 264 }
371 265
372 - Future<T> offNamed<T>(  
373 - String page, {  
374 - dynamic arguments,  
375 - Map<String, String>? parameters,  
376 - }) async {  
377 - history.removeLast();  
378 - return toNamed<T>(page, arguments: arguments, parameters: parameters); 266 + bool _canPopHistory() {
  267 + return history.length > 1;
379 } 268 }
380 269
381 - /// Removes routes according to [PopMode]  
382 - /// until it reaches the specifc [fullRoute],  
383 - /// DOES NOT remove the [fullRoute]  
384 - Future<void> backUntil(  
385 - String fullRoute, {  
386 - PopMode popMode = PopMode.Page,  
387 - }) async {  
388 - // remove history or page entries until you meet route  
389 - var iterator = currentConfiguration;  
390 - while (_canPop(popMode) &&  
391 - iterator != null &&  
392 - iterator.location != fullRoute) {  
393 - await _pop(popMode);  
394 - // replace iterator  
395 - iterator = currentConfiguration;  
396 - }  
397 - refresh(); 270 + bool _canPopPage() {
  271 + final currentTreeBranch = currentConfiguration?.currentTreeBranch;
  272 + if (currentTreeBranch == null) return false;
  273 + return currentTreeBranch.length > 1 ? true : _canPopHistory();
398 } 274 }
399 275
400 - Future<bool> handlePopupRoutes({  
401 - Object? result,  
402 - }) async {  
403 - Route? currentRoute;  
404 - navigatorKey.currentState!.popUntil((route) {  
405 - currentRoute = route;  
406 - return true;  
407 - });  
408 - if (currentRoute is PopupRoute) {  
409 - return await navigatorKey.currentState!.maybePop(result);  
410 - }  
411 - return false; 276 + Future<GetNavConfig?> _doPopHistory() async {
  277 + return await _unsafeHistoryRemoveAt(history.length - 1);
412 } 278 }
413 279
414 - @override  
415 - Future<bool> popRoute({  
416 - Object? result,  
417 - PopMode popMode = PopMode.Page,  
418 - }) async {  
419 - //Returning false will cause the entire app to be popped.  
420 - final wasPopup = await handlePopupRoutes(result: result);  
421 - if (wasPopup) return true;  
422 - final _popped = await _pop(popMode);  
423 - refresh();  
424 - if (_popped != null) {  
425 - //emulate the old pop with result  
426 - return true; 280 + // @override
  281 + // Future<void> setInitialRoutePath(GetNavConfig configuration) async {
  282 + // //no need to clear history with Reorder route strategy
  283 + // // _unsafeHistoryClear();
  284 + // // _resultCompleter.clear();
  285 + // await pushHistory(configuration);
  286 + // }
  287 +
  288 + Future<GetNavConfig?> _doPopPage() async {
  289 + final currentBranch = currentConfiguration?.currentTreeBranch;
  290 + if (currentBranch != null && currentBranch.length > 1) {
  291 + //remove last part only
  292 + final remaining = currentBranch.take(currentBranch.length - 1);
  293 + final prevHistoryEntry =
  294 + history.length > 1 ? history[history.length - 2] : null;
  295 +
  296 + //check if current route is the same as the previous route
  297 + if (prevHistoryEntry != null) {
  298 + //if so, pop the entire history entry
  299 + final newLocation = remaining.last.name;
  300 + final prevLocation = prevHistoryEntry.location;
  301 + if (newLocation == prevLocation) {
  302 + //pop the entire history entry
  303 + return await _popHistory();
  304 + }
  305 + }
  306 +
  307 + //create a new route with the remaining tree branch
  308 + final res = await _popHistory();
  309 + await _pushHistory(
  310 + GetNavConfig(
  311 + currentTreeBranch: remaining.toList(),
  312 + location: remaining.last.name,
  313 + state: null, //TOOD: persist state??
  314 + ),
  315 + );
  316 + return res;
  317 + } else {
  318 + //remove entire entry
  319 + return await _popHistory();
427 } 320 }
428 - return false;  
429 } 321 }
430 322
431 - final _allCompleters = <GetPage, Completer>{};  
432 -  
433 bool _onPopVisualRoute(Route<dynamic> route, dynamic result) { 323 bool _onPopVisualRoute(Route<dynamic> route, dynamic result) {
434 final didPop = route.didPop(result); 324 final didPop = route.didPop(result);
435 if (!didPop) { 325 if (!didPop) {
@@ -452,21 +342,89 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -452,21 +342,89 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
452 342
453 return true; 343 return true;
454 } 344 }
  345 +
  346 + Future<GetNavConfig?> _pop(PopMode mode) async {
  347 + switch (mode) {
  348 + case PopMode.History:
  349 + return await _popHistory();
  350 + case PopMode.Page:
  351 + return await _popPage();
  352 + default:
  353 + return null;
  354 + }
  355 + }
  356 +
  357 + Future<GetNavConfig?> _popHistory() async {
  358 + if (!_canPopHistory()) return null;
  359 + return await _doPopHistory();
  360 + }
  361 +
  362 + Future<GetNavConfig?> _popPage() async {
  363 + if (!_canPopPage()) return null;
  364 + return await _doPopPage();
  365 + }
  366 +
  367 + Future<void> _pushHistory(GetNavConfig config) async {
  368 + if (config.currentPage!.preventDuplicates) {
  369 + final originalEntryIndex =
  370 + history.indexWhere((element) => element.location == config.location);
  371 + if (originalEntryIndex >= 0) {
  372 + switch (preventDuplicateHandlingMode) {
  373 + case PreventDuplicateHandlingMode.PopUntilOriginalRoute:
  374 + await backUntil(config.location!, popMode: PopMode.Page);
  375 + break;
  376 + case PreventDuplicateHandlingMode.ReorderRoutes:
  377 + await _unsafeHistoryRemoveAt(originalEntryIndex);
  378 + await _unsafeHistoryAdd(config);
  379 + break;
  380 + case PreventDuplicateHandlingMode.DoNothing:
  381 + default:
  382 + break;
  383 + }
  384 + return;
  385 + }
  386 + }
  387 + await _unsafeHistoryAdd(config);
  388 + }
  389 +
  390 + Future<void> _removeHistoryEntry(GetNavConfig entry) async {
  391 + await _unsafeHistoryRemove(entry);
  392 + }
  393 +
  394 + Future<void> _unsafeHistoryAdd(GetNavConfig config) async {
  395 + final res = await runMiddleware(config);
  396 + if (res == null) return;
  397 + history.add(res);
  398 + }
  399 +
  400 + Future<void> _unsafeHistoryRemove(GetNavConfig config) async {
  401 + var index = history.indexOf(config);
  402 + if (index >= 0) await _unsafeHistoryRemoveAt(index);
  403 + }
  404 +
  405 + Future<GetNavConfig?> _unsafeHistoryRemoveAt(int index) async {
  406 + if (index == history.length - 1 && history.length > 1) {
  407 + //removing WILL update the current route
  408 + final toCheck = history[history.length - 2];
  409 + final resMiddleware = await runMiddleware(toCheck);
  410 + if (resMiddleware == null) return null;
  411 + history[history.length - 2] = resMiddleware;
  412 + }
  413 + return history.removeAt(index);
  414 + }
455 } 415 }
456 416
457 class GetNavigator extends Navigator { 417 class GetNavigator extends Navigator {
458 - GetNavigator(  
459 - {GlobalKey<NavigatorState>? key,  
460 - bool Function(Route<dynamic>, dynamic)? onPopPage,  
461 - required List<GetPage> pages,  
462 - List<NavigatorObserver>? observers,  
463 - bool reportsRouteUpdateToEngine = false,  
464 - TransitionDelegate? transitionDelegate,  
465 - String? initialRoute})  
466 - : super( 418 + GetNavigator({
  419 + GlobalKey<NavigatorState>? key,
  420 + bool Function(Route<dynamic>, dynamic)? onPopPage,
  421 + required List<Page> pages,
  422 + List<NavigatorObserver>? observers,
  423 + bool reportsRouteUpdateToEngine = false,
  424 + TransitionDelegate? transitionDelegate,
  425 + }) : super(
467 //keys should be optional 426 //keys should be optional
468 key: key, 427 key: key,
469 - initialRoute: initialRoute ?? '/',  
470 onPopPage: onPopPage ?? 428 onPopPage: onPopPage ??
471 (route, result) { 429 (route, result) {
472 final didPop = route.didPop(result); 430 final didPop = route.didPop(result);
@@ -475,17 +433,6 @@ class GetNavigator extends Navigator { @@ -475,17 +433,6 @@ class GetNavigator extends Navigator {
475 } 433 }
476 return true; 434 return true;
477 }, 435 },
478 - onGenerateRoute: (RouteSettings settings) {  
479 - final selectedPageList =  
480 - pages.where((element) => element.name == settings.name);  
481 - if (selectedPageList.isNotEmpty) {  
482 - final selectedPage = selectedPageList.first;  
483 - return GetPageRoute(  
484 - page: selectedPage.page,  
485 - settings: settings,  
486 - );  
487 - }  
488 - },  
489 reportsRouteUpdateToEngine: reportsRouteUpdateToEngine, 436 reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
490 pages: pages, 437 pages: pages,
491 observers: [ 438 observers: [
@@ -496,3 +443,44 @@ class GetNavigator extends Navigator { @@ -496,3 +443,44 @@ class GetNavigator extends Navigator {
496 transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(), 443 transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
497 ); 444 );
498 } 445 }
  446 +
  447 +/// Enables the user to customize the intended pop behavior
  448 +///
  449 +/// Goes to either the previous history entry or the previous page entry
  450 +///
  451 +/// e.g. if the user navigates to these pages
  452 +/// 1) /home
  453 +/// 2) /home/products/1234
  454 +///
  455 +/// when popping on [History] mode, it will emulate a browser back button.
  456 +///
  457 +/// so the new history stack will be:
  458 +/// 1) /home
  459 +///
  460 +/// when popping on [Page] mode, it will only remove the last part of the route
  461 +/// so the new history stack will be:
  462 +/// 1) /home
  463 +/// 2) /home/products
  464 +///
  465 +/// another pop will change the history stack to:
  466 +/// 1) /home
  467 +enum PopMode {
  468 + History,
  469 + Page,
  470 +}
  471 +
  472 +/// Enables the user to customize the behavior when pushing multiple routes that
  473 +/// shouldn't be duplicates
  474 +enum PreventDuplicateHandlingMode {
  475 + /// Removes the history entries until it reaches the old route
  476 + PopUntilOriginalRoute,
  477 +
  478 + /// Simply don't push the new route
  479 + DoNothing,
  480 +
  481 + /// Recommended - Moves the old route entry to the front
  482 + ///
  483 + /// With this mode, you guarantee there will be only one
  484 + /// route entry for each location
  485 + ReorderRoutes
  486 +}