Jonny Borges
Committed by GitHub

Merge pull request #2087 from Bdaya-Dev/master

Minor improvements with small breaking changes
@@ -75,9 +75,7 @@ class HomeView extends GetView<HomeController> { @@ -75,9 +75,7 @@ class HomeView extends GetView<HomeController> {
75 shape: StadiumBorder(), 75 shape: StadiumBorder(),
76 ), 76 ),
77 onPressed: () async { 77 onPressed: () async {
78 - final data =  
79 await Get.rootDelegate.toNamed('/home/country'); 78 await Get.rootDelegate.toNamed('/home/country');
80 - print('DATA: $data');  
81 }, 79 },
82 child: Text( 80 child: Text(
83 'fetch_country'.tr, 81 'fetch_country'.tr,
  1 +import 'dart:async';
  2 +
  3 +import 'package:get/get.dart';
  4 +import 'package:async/async.dart';
  5 +
  6 +class SplashService extends GetxService {
  7 + final welcomeStr = ['GetX', 'Rules!'];
  8 + final activeStr = 0.obs;
  9 +
  10 + final memo = AsyncMemoizer<void>();
  11 + Future<void> init() {
  12 + return memo.runOnce(_initFunction);
  13 + }
  14 +
  15 + void _changeActiveString() {
  16 + activeStr.value = (activeStr.value + 1) % welcomeStr.length;
  17 + }
  18 +
  19 + Future<void> _initFunction() async {
  20 + final t = Timer.periodic(
  21 + Duration(milliseconds: 500),
  22 + (t) => _changeActiveString(),
  23 + );
  24 + //simulate some long running operation
  25 + await Future.delayed(Duration(seconds: 5));
  26 + //cancel the timer once we are done
  27 + t.cancel();
  28 + }
  29 +}
  1 +import 'package:flutter/material.dart';
  2 +
  3 +import 'package:get/get.dart';
  4 +
  5 +import '../controllers/splash_service.dart';
  6 +
  7 +class SplashView extends GetView<SplashService> {
  8 + @override
  9 + Widget build(BuildContext context) {
  10 + return Scaffold(
  11 + body: Center(
  12 + child: Column(
  13 + mainAxisSize: MainAxisSize.min,
  14 + children: [
  15 + Obx(
  16 + () => Text(
  17 + controller.welcomeStr[controller.activeStr.value],
  18 + style: TextStyle(fontSize: 20),
  19 + ),
  20 + ),
  21 + CircularProgressIndicator(),
  22 + ],
  23 + ),
  24 + ),
  25 + );
  26 + }
  27 +}
  1 +import 'package:example_nav2/app/modules/splash/controllers/splash_service.dart';
  2 +import 'package:example_nav2/app/modules/splash/views/splash_view.dart';
1 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
2 import 'package:get/get.dart'; 4 import 'package:get/get.dart';
3 5
@@ -10,10 +12,23 @@ void main() { @@ -10,10 +12,23 @@ void main() {
10 title: "Application", 12 title: "Application",
11 initialBinding: BindingsBuilder( 13 initialBinding: BindingsBuilder(
12 () { 14 () {
  15 + Get.put(SplashService());
13 Get.put(AuthService()); 16 Get.put(AuthService());
14 }, 17 },
15 ), 18 ),
16 getPages: AppPages.routes, 19 getPages: AppPages.routes,
  20 + builder: (context, child) {
  21 + return FutureBuilder<void>(
  22 + key: ValueKey('initFuture'),
  23 + future: Get.find<SplashService>().init(),
  24 + builder: (context, snapshot) {
  25 + if (snapshot.connectionState == ConnectionState.done) {
  26 + return child ?? SizedBox.shrink();
  27 + }
  28 + return SplashView();
  29 + },
  30 + );
  31 + },
17 // routeInformationParser: GetInformationParser( 32 // routeInformationParser: GetInformationParser(
18 // // initialRoute: Routes.HOME, 33 // // initialRoute: Routes.HOME,
19 // ), 34 // ),
@@ -2,8 +2,6 @@ @@ -2,8 +2,6 @@
2 // Generated file. Do not edit. 2 // Generated file. Do not edit.
3 // 3 //
4 4
5 -// clang-format off  
6 -  
7 #include "generated_plugin_registrant.h" 5 #include "generated_plugin_registrant.h"
8 6
9 7
@@ -2,8 +2,6 @@ @@ -2,8 +2,6 @@
2 // Generated file. Do not edit. 2 // Generated file. Do not edit.
3 // 3 //
4 4
5 -// clang-format off  
6 -  
7 #ifndef GENERATED_PLUGIN_REGISTRANT_ 5 #ifndef GENERATED_PLUGIN_REGISTRANT_
8 #define GENERATED_PLUGIN_REGISTRANT_ 6 #define GENERATED_PLUGIN_REGISTRANT_
9 7
@@ -162,30 +162,25 @@ class GetInstance { @@ -162,30 +162,25 @@ class GetInstance {
162 }) { 162 }) {
163 final key = _getKey(S, name); 163 final key = _getKey(S, name);
164 164
  165 + _InstanceBuilderFactory<S>? dep;
165 if (_singl.containsKey(key)) { 166 if (_singl.containsKey(key)) {
166 - final dep = _singl[key];  
167 - if (dep != null && dep.isDirty) {  
168 - _singl[key] = _InstanceBuilderFactory<S>(  
169 - isSingleton,  
170 - builder,  
171 - permanent,  
172 - false,  
173 - fenix,  
174 - name,  
175 - lateRemove: dep as _InstanceBuilderFactory<S>,  
176 - );  
177 - } 167 + final _dep = _singl[key];
  168 + if (_dep == null || !_dep.isDirty) {
  169 + return;
178 } else { 170 } else {
  171 + dep = _dep as _InstanceBuilderFactory<S>;
  172 + }
  173 + }
179 _singl[key] = _InstanceBuilderFactory<S>( 174 _singl[key] = _InstanceBuilderFactory<S>(
180 - isSingleton,  
181 - builder,  
182 - permanent,  
183 - false,  
184 - fenix,  
185 - name, 175 + isSingleton: isSingleton,
  176 + builderFunc: builder,
  177 + permanent: permanent,
  178 + isInit: false,
  179 + fenix: fenix,
  180 + tag: name,
  181 + lateRemove: dep,
186 ); 182 );
187 } 183 }
188 - }  
189 184
190 /// Initializes the dependencies for a Class Instance [S] (or tag), 185 /// Initializes the dependencies for a Class Instance [S] (or tag),
191 /// If its a Controller, it starts the lifecycle process. 186 /// If its a Controller, it starts the lifecycle process.
@@ -519,14 +514,14 @@ class _InstanceBuilderFactory<S> { @@ -519,14 +514,14 @@ class _InstanceBuilderFactory<S> {
519 514
520 String? tag; 515 String? tag;
521 516
522 - _InstanceBuilderFactory(  
523 - this.isSingleton,  
524 - this.builderFunc,  
525 - this.permanent,  
526 - this.isInit,  
527 - this.fenix,  
528 - this.tag, {  
529 - this.lateRemove, 517 + _InstanceBuilderFactory({
  518 + required this.isSingleton,
  519 + required this.builderFunc,
  520 + required this.permanent,
  521 + required this.isInit,
  522 + required this.fenix,
  523 + required this.tag,
  524 + required this.lateRemove,
530 }); 525 });
531 526
532 void _showInitLog() { 527 void _showInitLog() {
@@ -4,6 +4,7 @@ export 'src/bottomsheet/bottomsheet.dart'; @@ -4,6 +4,7 @@ export 'src/bottomsheet/bottomsheet.dart';
4 export 'src/extension_navigation.dart'; 4 export 'src/extension_navigation.dart';
5 export 'src/nav2/get_information_parser.dart'; 5 export 'src/nav2/get_information_parser.dart';
6 export 'src/nav2/get_nav_config.dart'; 6 export 'src/nav2/get_nav_config.dart';
  7 +export 'src/nav2/get_navigator.dart';
7 export 'src/nav2/get_router_delegate.dart'; 8 export 'src/nav2/get_router_delegate.dart';
8 export 'src/nav2/router_outlet.dart'; 9 export 'src/nav2/router_outlet.dart';
9 export 'src/root/get_cupertino_app.dart'; 10 export 'src/root/get_cupertino_app.dart';
@@ -56,5 +56,5 @@ class GetNavConfig extends RouteInformation { @@ -56,5 +56,5 @@ class GetNavConfig extends RouteInformation {
56 56
57 @override 57 @override
58 String toString() => ''' 58 String toString() => '''
59 -======GetNavConfig=====\ncurrentTreeBranch: $currentTreeBranch\ncurrentPage: $currentPage\n======GetNavConfig====='''; 59 +======GetNavConfig=====\nlocation: $location\ncurrentTreeBranch: $currentTreeBranch\n======GetNavConfig=====''';
60 } 60 }
  1 +import 'package:flutter/widgets.dart';
  2 +import '../routes/default_route.dart';
  3 +import '../routes/get_route.dart';
  4 +
  5 +class GetNavigator extends Navigator {
  6 + GetNavigator.onGenerateRoute({
  7 + GlobalKey<NavigatorState>? key,
  8 + bool Function(Route<dynamic>, dynamic)? onPopPage,
  9 + required List<GetPage> pages,
  10 + List<NavigatorObserver>? observers,
  11 + bool reportsRouteUpdateToEngine = false,
  12 + TransitionDelegate? transitionDelegate,
  13 + String? initialRoute,
  14 + }) : super(
  15 + //keys should be optional
  16 + key: key,
  17 + initialRoute: initialRoute,
  18 + onPopPage: onPopPage ??
  19 + (route, result) {
  20 + final didPop = route.didPop(result);
  21 + if (!didPop) {
  22 + return false;
  23 + }
  24 + return true;
  25 + },
  26 + onGenerateRoute: (settings) {
  27 + final selectedPageList =
  28 + pages.where((element) => element.name == settings.name);
  29 + if (selectedPageList.isNotEmpty) {
  30 + final selectedPage = selectedPageList.first;
  31 + return GetPageRoute(
  32 + page: selectedPage.page,
  33 + settings: settings,
  34 + );
  35 + }
  36 + },
  37 + reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
  38 + pages: pages,
  39 + observers: [
  40 + // GetObserver(),
  41 + ...?observers,
  42 + ],
  43 + transitionDelegate:
  44 + transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
  45 + );
  46 +
  47 + GetNavigator({
  48 + GlobalKey<NavigatorState>? key,
  49 + bool Function(Route<dynamic>, dynamic)? onPopPage,
  50 + required List<GetPage> pages,
  51 + List<NavigatorObserver>? observers,
  52 + bool reportsRouteUpdateToEngine = false,
  53 + TransitionDelegate? transitionDelegate,
  54 + String? initialRoute,
  55 + }) : super(
  56 + //keys should be optional
  57 + key: key,
  58 + initialRoute: initialRoute,
  59 + onPopPage: onPopPage ??
  60 + (route, result) {
  61 + final didPop = route.didPop(result);
  62 + if (!didPop) {
  63 + return false;
  64 + }
  65 + return true;
  66 + },
  67 + reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
  68 + pages: pages,
  69 + observers: [
  70 + // GetObserver(),
  71 + ...?observers,
  72 + ],
  73 + transitionDelegate:
  74 + transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
  75 + );
  76 +}
@@ -2,9 +2,50 @@ import 'dart:async'; @@ -2,9 +2,50 @@ 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 -  
6 import '../../../get.dart'; 5 import '../../../get.dart';
7 import '../../../get_state_manager/src/simple/list_notifier.dart'; 6 import '../../../get_state_manager/src/simple/list_notifier.dart';
  7 +import 'get_navigator.dart';
  8 +
  9 +/// Enables the user to customize the intended pop behavior
  10 +///
  11 +/// Goes to either the previous history entry or the previous page entry
  12 +///
  13 +/// e.g. if the user navigates to these pages
  14 +/// 1) /home
  15 +/// 2) /home/products/1234
  16 +///
  17 +/// when popping on [History] mode, it will emulate a browser back button.
  18 +///
  19 +/// so the new history stack will be:
  20 +/// 1) /home
  21 +///
  22 +/// when popping on [Page] mode, it will only remove the last part of the route
  23 +/// so the new history stack will be:
  24 +/// 1) /home
  25 +/// 2) /home/products
  26 +///
  27 +/// another pop will change the history stack to:
  28 +/// 1) /home
  29 +enum PopMode {
  30 + History,
  31 + Page,
  32 +}
  33 +
  34 +/// Enables the user to customize the behavior when pushing multiple routes that
  35 +/// shouldn't be duplicates
  36 +enum PreventDuplicateHandlingMode {
  37 + /// Removes the history entries until it reaches the old route
  38 + PopUntilOriginalRoute,
  39 +
  40 + /// Simply don't push the new route
  41 + DoNothing,
  42 +
  43 + /// Recommended - Moves the old route entry to the front
  44 + ///
  45 + /// With this mode, you guarantee there will be only one
  46 + /// route entry for each location
  47 + ReorderRoutes
  48 +}
8 49
9 class GetDelegate extends RouterDelegate<GetNavConfig> 50 class GetDelegate extends RouterDelegate<GetNavConfig>
10 with ListNotifierSingleMixin { 51 with ListNotifierSingleMixin {
@@ -17,7 +58,10 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -17,7 +58,10 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
17 final List<NavigatorObserver>? navigatorObservers; 58 final List<NavigatorObserver>? navigatorObservers;
18 final TransitionDelegate<dynamic>? transitionDelegate; 59 final TransitionDelegate<dynamic>? transitionDelegate;
19 60
20 - final _allCompleters = <GetPage, Completer>{}; 61 + final Iterable<GetPage> Function(GetNavConfig currentNavStack)?
  62 + pickPagesForRootNavigator;
  63 +
  64 + GlobalKey<NavigatorState> get navigatorKey => Get.key;
21 65
22 GetDelegate({ 66 GetDelegate({
23 GetPage? notFoundRoute, 67 GetPage? notFoundRoute,
@@ -26,6 +70,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -26,6 +70,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
26 this.backButtonPopMode = PopMode.History, 70 this.backButtonPopMode = PopMode.History,
27 this.preventDuplicateHandlingMode = 71 this.preventDuplicateHandlingMode =
28 PreventDuplicateHandlingMode.ReorderRoutes, 72 PreventDuplicateHandlingMode.ReorderRoutes,
  73 + this.pickPagesForRootNavigator,
29 }) : notFoundRoute = notFoundRoute ?? 74 }) : notFoundRoute = notFoundRoute ??
30 GetPage( 75 GetPage(
31 name: '/404', 76 name: '/404',
@@ -36,157 +81,48 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -36,157 +81,48 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
36 Get.log('GetDelegate is created !'); 81 Get.log('GetDelegate is created !');
37 } 82 }
38 83
39 - @override  
40 - GetNavConfig? get currentConfiguration {  
41 - if (history.isEmpty) return null;  
42 - final route = history.last;  
43 - return route;  
44 - }  
45 -  
46 - GlobalKey<NavigatorState> get navigatorKey => Get.key;  
47 -  
48 - Map<String, String> get parameters {  
49 - return currentConfiguration?.currentPage?.parameters ?? {};  
50 - }  
51 -  
52 - T arguments<T>() {  
53 - return currentConfiguration?.currentPage?.arguments as T;  
54 - }  
55 -  
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,  
62 - }) async {  
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;  
71 - }  
72 - refresh();  
73 - }  
74 -  
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 - );  
91 - }  
92 -  
93 - // void _unsafeHistoryClear() {  
94 - // history.clear();  
95 - // }  
96 -  
97 - Future<bool> canPopHistory() {  
98 - return SynchronousFuture(_canPopHistory());  
99 - }  
100 -  
101 - Future<bool> canPopPage() {  
102 - return SynchronousFuture(_canPopPage()); 84 + Future<GetNavConfig?> runMiddleware(GetNavConfig config) async {
  85 + final middlewares = config.currentTreeBranch.last.middlewares;
  86 + if (middlewares == null) {
  87 + return config;
103 } 88 }
104 -  
105 - /// gets the visual pages from the current history entry  
106 - ///  
107 - /// visual pages must have [participatesInRootNavigator] set to true  
108 - List<GetPage> getVisualPages() {  
109 - final currentHistory = currentConfiguration;  
110 - if (currentHistory == null) return <GetPage>[];  
111 -  
112 - final res = currentHistory.currentTreeBranch  
113 - .where((r) => r.participatesInRootNavigator != null);  
114 - if (res.length == 0) {  
115 - //default behavoir, all routes participate in root navigator  
116 - return history.map((e) => e.currentPage!).toList();  
117 - } else {  
118 - //user specified at least one participatesInRootNavigator  
119 - return res  
120 - .where((element) => element.participatesInRootNavigator == true)  
121 - .toList(); 89 + var iterator = config;
  90 + for (var item in middlewares) {
  91 + var redirectRes = await item.redirectDelegate(iterator);
  92 + if (redirectRes == null) return null;
  93 + iterator = redirectRes;
122 } 94 }
  95 + return iterator;
123 } 96 }
124 97
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; 98 + Future<void> _unsafeHistoryAdd(GetNavConfig config) async {
  99 + final res = await runMiddleware(config);
  100 + if (res == null) return;
  101 + history.add(res);
142 } 102 }
143 103
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(); 104 + Future<void> _unsafeHistoryRemove(GetNavConfig config) async {
  105 + var index = history.indexOf(config);
  106 + if (index >= 0) await _unsafeHistoryRemoveAt(index);
155 } 107 }
156 108
157 - await popRoute(result: result);  
158 - return toNamed(page, arguments: arguments, parameters: parameters); 109 + Future<GetNavConfig?> _unsafeHistoryRemoveAt(int index) async {
  110 + if (index == history.length - 1 && history.length > 1) {
  111 + //removing WILL update the current route
  112 + final toCheck = history[history.length - 2];
  113 + final resMiddleware = await runMiddleware(toCheck);
  114 + if (resMiddleware == null) return null;
  115 + history[history.length - 2] = resMiddleware;
159 } 116 }
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); 117 + return history.removeAt(index);
168 } 118 }
169 119
170 - Future<GetNavConfig?> popHistory() async {  
171 - return await _popHistory(); 120 + T arguments<T>() {
  121 + return currentConfiguration?.currentPage?.arguments as T;
172 } 122 }
173 123
174 - // returns the popped page  
175 - @override  
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; 124 + Map<String, String> get parameters {
  125 + return currentConfiguration?.currentPage?.parameters ?? {};
190 } 126 }
191 127
192 /// Adds a new history entry and waits for the result 128 /// Adds a new history entry and waits for the result
@@ -201,90 +137,59 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -201,90 +137,59 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
201 } 137 }
202 } 138 }
203 139
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; 140 + Future<void> _removeHistoryEntry(GetNavConfig entry) async {
  141 + await _unsafeHistoryRemove(entry);
216 } 142 }
217 143
218 - @override  
219 - Future<void> setNewRoutePath(GetNavConfig configuration) async {  
220 - await pushHistory(configuration); 144 + Future<void> _pushHistory(GetNavConfig config) async {
  145 + if (config.currentPage!.preventDuplicates) {
  146 + final originalEntryIndex =
  147 + history.indexWhere((element) => element.location == config.location);
  148 + if (originalEntryIndex >= 0) {
  149 + switch (preventDuplicateHandlingMode) {
  150 + case PreventDuplicateHandlingMode.PopUntilOriginalRoute:
  151 + await backUntil(config.location!, popMode: PopMode.Page);
  152 + break;
  153 + case PreventDuplicateHandlingMode.ReorderRoutes:
  154 + await _unsafeHistoryRemoveAt(originalEntryIndex);
  155 + await _unsafeHistoryAdd(config);
  156 + break;
  157 + case PreventDuplicateHandlingMode.DoNothing:
  158 + default:
  159 + break;
221 } 160 }
222 -  
223 - Future<T> toNamed<T>(  
224 - String page, {  
225 - dynamic arguments,  
226 - Map<String, String>? parameters,  
227 - }) async {  
228 - if (parameters != null) {  
229 - final uri = Uri(path: page, queryParameters: parameters);  
230 - page = uri.toString(); 161 + return;
231 } 162 }
232 -  
233 - final decoder = Get.routeTree.matchRoute(page, arguments: arguments);  
234 - decoder.replaceArguments(arguments);  
235 -  
236 - final completer = Completer<T>();  
237 -  
238 - if (decoder.route != null) {  
239 - _allCompleters[decoder.route!] = completer;  
240 - await pushHistory(  
241 - GetNavConfig(  
242 - currentTreeBranch: decoder.treeBranch,  
243 - location: page,  
244 - state: null, //TODO: persist state?  
245 - ),  
246 - );  
247 -  
248 - return completer.future;  
249 - } else {  
250 - ///TODO: IMPLEMENT ROUTE NOT FOUND  
251 -  
252 - return Future.value();  
253 } 163 }
  164 + await _unsafeHistoryAdd(config);
254 } 165 }
255 166
256 - bool _canPop(PopMode mode) {  
257 - switch (mode) {  
258 - case PopMode.History:  
259 - return _canPopHistory();  
260 - case PopMode.Page:  
261 - default:  
262 - return _canPopPage();  
263 - } 167 + Future<GetNavConfig?> _popHistory() async {
  168 + if (!_canPopHistory()) return null;
  169 + return await _doPopHistory();
264 } 170 }
265 171
266 - bool _canPopHistory() {  
267 - return history.length > 1; 172 + Future<GetNavConfig?> _doPopHistory() async {
  173 + return await _unsafeHistoryRemoveAt(history.length - 1);
268 } 174 }
269 175
270 - bool _canPopPage() {  
271 - final currentTreeBranch = currentConfiguration?.currentTreeBranch;  
272 - if (currentTreeBranch == null) return false;  
273 - return currentTreeBranch.length > 1 ? true : _canPopHistory(); 176 + Future<GetNavConfig?> _popPage() async {
  177 + if (!_canPopPage()) return null;
  178 + return await _doPopPage();
274 } 179 }
275 180
276 - Future<GetNavConfig?> _doPopHistory() async {  
277 - return await _unsafeHistoryRemoveAt(history.length - 1); 181 + Future<GetNavConfig?> _pop(PopMode mode) async {
  182 + switch (mode) {
  183 + case PopMode.History:
  184 + return await _popHistory();
  185 + case PopMode.Page:
  186 + return await _popPage();
  187 + default:
  188 + return null;
  189 + }
278 } 190 }
279 191
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 - 192 + // returns the popped page
288 Future<GetNavConfig?> _doPopPage() async { 193 Future<GetNavConfig?> _doPopPage() async {
289 final currentBranch = currentConfiguration?.currentTreeBranch; 194 final currentBranch = currentConfiguration?.currentTreeBranch;
290 if (currentBranch != null && currentBranch.length > 1) { 195 if (currentBranch != null && currentBranch.length > 1) {
@@ -320,167 +225,197 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -320,167 +225,197 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
320 } 225 }
321 } 226 }
322 227
323 - bool _onPopVisualRoute(Route<dynamic> route, dynamic result) {  
324 - final didPop = route.didPop(result);  
325 - if (!didPop) {  
326 - return false; 228 + Future<GetNavConfig?> popHistory() async {
  229 + return await _popHistory();
327 } 230 }
328 - final settings = route.settings;  
329 - if (settings is GetPage) {  
330 - final config = history.cast<GetNavConfig?>().firstWhere(  
331 - (element) => element?.currentPage == settings,  
332 - orElse: () => null,  
333 - );  
334 - if (config != null) {  
335 - _removeHistoryEntry(config); 231 +
  232 + bool _canPopHistory() {
  233 + return history.length > 1;
336 } 234 }
337 - if (_allCompleters.containsKey(settings)) {  
338 - _allCompleters[settings]?.complete(route.popped); 235 +
  236 + Future<bool> canPopHistory() {
  237 + return SynchronousFuture(_canPopHistory());
339 } 238 }
  239 +
  240 + bool _canPopPage() {
  241 + final currentTreeBranch = currentConfiguration?.currentTreeBranch;
  242 + if (currentTreeBranch == null) return false;
  243 + return currentTreeBranch.length > 1 ? true : _canPopHistory();
340 } 244 }
341 - refresh();  
342 245
343 - return true; 246 + Future<bool> canPopPage() {
  247 + return SynchronousFuture(_canPopPage());
344 } 248 }
345 249
346 - Future<GetNavConfig?> _pop(PopMode mode) async { 250 + bool _canPop(PopMode mode) {
347 switch (mode) { 251 switch (mode) {
348 case PopMode.History: 252 case PopMode.History:
349 - return await _popHistory(); 253 + return _canPopHistory();
350 case PopMode.Page: 254 case PopMode.Page:
351 - return await _popPage();  
352 default: 255 default:
353 - return null; 256 + return _canPopPage();
354 } 257 }
355 } 258 }
356 259
357 - Future<GetNavConfig?> _popHistory() async {  
358 - if (!_canPopHistory()) return null;  
359 - return await _doPopHistory(); 260 + /// gets the visual pages from the current history entry
  261 + ///
  262 + /// visual pages must have [GetPage.participatesInRootNavigator] set to true
  263 + Iterable<GetPage> getVisualPages(GetNavConfig currentHistory) {
  264 + final res = currentHistory.currentTreeBranch
  265 + .where((r) => r.participatesInRootNavigator != null);
  266 + if (res.length == 0) {
  267 + //default behavoir, all routes participate in root navigator
  268 + return history.map((e) => e.currentPage!);
  269 + } else {
  270 + //user specified at least one participatesInRootNavigator
  271 + return res
  272 + .where((element) => element.participatesInRootNavigator == true);
  273 + }
360 } 274 }
361 275
362 - Future<GetNavConfig?> _popPage() async {  
363 - if (!_canPopPage()) return null;  
364 - return await _doPopPage(); 276 + @override
  277 + Widget build(BuildContext context) {
  278 + final currentHistory = currentConfiguration;
  279 + final pages = currentHistory == null
  280 + ? <GetPage>[]
  281 + : pickPagesForRootNavigator?.call(currentHistory) ??
  282 + getVisualPages(currentHistory);
  283 + if (pages.length == 0) return SizedBox.shrink();
  284 + return GetNavigator(
  285 + key: navigatorKey,
  286 + onPopPage: _onPopVisualRoute,
  287 + pages: pages.toList(),
  288 + observers: [
  289 + GetObserver(),
  290 + ...?navigatorObservers,
  291 + ],
  292 + transitionDelegate:
  293 + transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
  294 + );
365 } 295 }
366 296
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; 297 + @override
  298 + Future<void> setNewRoutePath(GetNavConfig configuration) async {
  299 + await pushHistory(configuration);
383 } 300 }
384 - return; 301 +
  302 + @override
  303 + GetNavConfig? get currentConfiguration {
  304 + if (history.isEmpty) return null;
  305 + final route = history.last;
  306 + return route;
385 } 307 }
  308 +
  309 + Future<void> toNamed(
  310 + String page, {
  311 + dynamic arguments,
  312 + Map<String, String>? parameters,
  313 + }) async {
  314 + if (parameters != null) {
  315 + final uri = Uri(path: page, queryParameters: parameters);
  316 + page = uri.toString();
  317 + }
  318 +
  319 + final decoder = Get.routeTree.matchRoute(page, arguments: arguments);
  320 + decoder.replaceArguments(arguments);
  321 +
  322 + if (decoder.route != null) {
  323 + await pushHistory(
  324 + GetNavConfig(
  325 + currentTreeBranch: decoder.treeBranch,
  326 + location: page,
  327 + state: null, //TODO: persist state?
  328 + ),
  329 + );
  330 + } else {
  331 + await pushHistory(
  332 + GetNavConfig(
  333 + currentTreeBranch: [notFoundRoute],
  334 + location: notFoundRoute.name,
  335 + state: null, //TODO: persist state?
  336 + ),
  337 + );
386 } 338 }
387 - await _unsafeHistoryAdd(config);  
388 } 339 }
389 340
390 - Future<void> _removeHistoryEntry(GetNavConfig entry) async {  
391 - await _unsafeHistoryRemove(entry); 341 + //pops the previous route (if there is one) and goes to new route
  342 + Future<void> offNamed(
  343 + String page, {
  344 + dynamic arguments,
  345 + Map<String, String>? parameters,
  346 + PopMode popMode = PopMode.History,
  347 + }) async {
  348 + await popRoute(popMode: popMode);
  349 + return toNamed(page, arguments: arguments, parameters: parameters);
392 } 350 }
393 351
394 - Future<void> _unsafeHistoryAdd(GetNavConfig config) async {  
395 - final res = await runMiddleware(config);  
396 - if (res == null) return;  
397 - history.add(res); 352 + /// Removes routes according to [PopMode]
  353 + /// until it reaches the specifc [fullRoute],
  354 + /// DOES NOT remove the [fullRoute]
  355 + Future<void> backUntil(
  356 + String fullRoute, {
  357 + PopMode popMode = PopMode.History,
  358 + }) async {
  359 + // remove history or page entries until you meet route
  360 + var iterator = currentConfiguration;
  361 + while (_canPop(popMode) &&
  362 + iterator != null &&
  363 + iterator.location != fullRoute) {
  364 + await _pop(popMode);
  365 + // replace iterator
  366 + iterator = currentConfiguration;
  367 + }
  368 + refresh();
398 } 369 }
399 370
400 - Future<void> _unsafeHistoryRemove(GetNavConfig config) async {  
401 - var index = history.indexOf(config);  
402 - if (index >= 0) await _unsafeHistoryRemoveAt(index); 371 + Future<bool> handlePopupRoutes({
  372 + Object? result,
  373 + }) async {
  374 + Route? currentRoute;
  375 + navigatorKey.currentState!.popUntil((route) {
  376 + currentRoute = route;
  377 + return true;
  378 + });
  379 + if (currentRoute is PopupRoute) {
  380 + return await navigatorKey.currentState!.maybePop(result);
  381 + }
  382 + return false;
403 } 383 }
404 384
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; 385 + @override
  386 + Future<bool> popRoute({
  387 + Object? result,
  388 + PopMode? popMode,
  389 + }) async {
  390 + //Returning false will cause the entire app to be popped.
  391 + final wasPopup = await handlePopupRoutes(result: result);
  392 + if (wasPopup) return true;
  393 + final _popped = await _pop(popMode ?? backButtonPopMode);
  394 + refresh();
  395 + if (_popped != null) {
  396 + //emulate the old pop with result
  397 + return true;
412 } 398 }
413 - return history.removeAt(index); 399 + return false;
414 } 400 }
415 -}  
416 401
417 -class GetNavigator extends Navigator {  
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(  
426 - //keys should be optional  
427 - key: key,  
428 - onPopPage: onPopPage ??  
429 - (route, result) { 402 + bool _onPopVisualRoute(Route<dynamic> route, dynamic result) {
430 final didPop = route.didPop(result); 403 final didPop = route.didPop(result);
431 if (!didPop) { 404 if (!didPop) {
432 return false; 405 return false;
433 } 406 }
434 - return true;  
435 - },  
436 - reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,  
437 - pages: pages,  
438 - observers: [  
439 - // GetObserver(),  
440 - if (observers != null) ...observers,  
441 - ],  
442 - transitionDelegate:  
443 - transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(), 407 + final settings = route.settings;
  408 + if (settings is GetPage) {
  409 + final config = history.cast<GetNavConfig?>().firstWhere(
  410 + (element) => element?.currentPage == settings,
  411 + orElse: () => null,
444 ); 412 );
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, 413 + if (config != null) {
  414 + _removeHistoryEntry(config);
  415 + }
  416 + }
  417 + refresh();
480 418
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 419 + return true;
  420 + }
486 } 421 }
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
2 2
  3 +import 'default_route.dart';
  4 +
3 enum Transition { 5 enum Transition {
4 fade, 6 fade,
5 fadeIn, 7 fadeIn,
@@ -20,3 +22,4 @@ enum Transition { @@ -20,3 +22,4 @@ enum Transition {
20 } 22 }
21 23
22 typedef GetPageBuilder = Widget Function(); 24 typedef GetPageBuilder = Widget Function();
  25 +typedef GetRouteAwarePageBuilder<T> = Widget Function([GetPageRoute<T>? route]);
@@ -569,7 +569,4 @@ class BindError<T> extends Error { @@ -569,7 +569,4 @@ class BindError<T> extends Error {
569 /// instance of Bindings to manage the 569 /// instance of Bindings to manage the
570 /// dependencies() (via Get.put()) for the Route you are opening. 570 /// dependencies() (via Get.put()) for the Route you are opening.
571 // ignore: one_member_abstracts 571 // ignore: one_member_abstracts
572 -abstract class Binding extends BindingsInterface<List<Bind>> {  
573 - @override  
574 - List<Bind> dependencies();  
575 -} 572 +abstract class Binding extends BindingsInterface<Iterable<Bind>> {}
@@ -24,36 +24,32 @@ typedef ValueBuilderBuilder<T> = Widget Function( @@ -24,36 +24,32 @@ typedef ValueBuilderBuilder<T> = Widget Function(
24 /// ), 24 /// ),
25 /// ``` 25 /// ```
26 class ValueBuilder<T> extends StatefulWidget { 26 class ValueBuilder<T> extends StatefulWidget {
27 - final T? initialValue; 27 + final T initialValue;
28 final ValueBuilderBuilder<T> builder; 28 final ValueBuilderBuilder<T> builder;
29 final void Function()? onDispose; 29 final void Function()? onDispose;
30 final void Function(T)? onUpdate; 30 final void Function(T)? onUpdate;
31 31
32 const ValueBuilder({ 32 const ValueBuilder({
33 Key? key, 33 Key? key,
34 - this.initialValue, 34 + required this.initialValue,
35 this.onDispose, 35 this.onDispose,
36 this.onUpdate, 36 this.onUpdate,
37 required this.builder, 37 required this.builder,
38 }) : super(key: key); 38 }) : super(key: key);
39 39
40 @override 40 @override
41 - _ValueBuilderState<T> createState() => _ValueBuilderState<T>(); 41 + _ValueBuilderState<T> createState() => _ValueBuilderState<T>(initialValue);
42 } 42 }
43 43
44 -class _ValueBuilderState<T> extends State<ValueBuilder<T?>> {  
45 - T? value; 44 +class _ValueBuilderState<T> extends State<ValueBuilder<T>> {
  45 + T value;
  46 + _ValueBuilderState(this.value);
46 47
47 - @override  
48 - void initState() {  
49 - super.initState();  
50 - value = widget.initialValue;  
51 - }  
52 48
53 @override 49 @override
54 Widget build(BuildContext context) => widget.builder(value, updater); 50 Widget build(BuildContext context) => widget.builder(value, updater);
55 51
56 - void updater(T? newValue) { 52 + void updater(T newValue) {
57 if (widget.onUpdate != null) { 53 if (widget.onUpdate != null) {
58 widget.onUpdate!(newValue); 54 widget.onUpdate!(newValue);
59 } 55 }
@@ -71,7 +67,6 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T?>> { @@ -71,7 +67,6 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T?>> {
71 } else if (value is StreamController) { 67 } else if (value is StreamController) {
72 (value as StreamController?)?.close(); 68 (value as StreamController?)?.close();
73 } 69 }
74 - value = null;  
75 } 70 }
76 } 71 }
77 72
  1 +import 'package:collection/collection.dart';
1 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
2 3
3 -import '../platform/platform.dart';  
4 -  
5 extension ContextExtensionss on BuildContext { 4 extension ContextExtensionss on BuildContext {
6 /// The same of [MediaQuery.of(context).size] 5 /// The same of [MediaQuery.of(context).size]
7 Size get mediaQuerySize => MediaQuery.of(this).size; 6 Size get mediaQuerySize => MediaQuery.of(this).size;
@@ -100,17 +99,44 @@ extension ContextExtensionss on BuildContext { @@ -100,17 +99,44 @@ extension ContextExtensionss on BuildContext {
100 /// True if width be larger than 800 99 /// True if width be larger than 800
101 bool get showNavbar => (width > 800); 100 bool get showNavbar => (width > 800);
102 101
103 - /// True if the shortestSide is smaller than 600p  
104 - bool get isPhone => (mediaQueryShortestSide < 600); 102 + /// True if the width is smaller than 600p
  103 + bool get isPhoneOrLess => width <= 600;
  104 +
  105 + /// True if the width is higher than 600p
  106 + bool get isPhoneOrWider => width >= 600;
  107 +
  108 + /// same as [isPhoneOrLess]
  109 + bool get isPhone => isPhoneOrLess;
  110 +
  111 + /// True if the width is smaller than 600p
  112 + bool get isSmallTabletOrLess => width <= 600;
  113 +
  114 + /// True if the width is higher than 600p
  115 + bool get isSmallTabletOrWider => width >= 600;
  116 +
  117 + /// same as [isSmallTabletOrLess]
  118 + bool get isSmallTablet => isSmallTabletOrLess;
  119 +
  120 + /// True if the width is smaller than 720p
  121 + bool get isLargeTabletOrLess => width <= 720;
105 122
106 - /// True if the shortestSide is largest than 600p  
107 - bool get isSmallTablet => (mediaQueryShortestSide >= 600); 123 + /// True if the width is higher than 720p
  124 + bool get isLargeTabletOrWider => width >= 720;
108 125
109 - /// True if the shortestSide is largest than 720p  
110 - bool get isLargeTablet => (mediaQueryShortestSide >= 720); 126 + /// same as [isLargeTabletOrLess]
  127 + bool get isLargeTablet => isLargeTabletOrLess;
111 128
112 /// True if the current device is Tablet 129 /// True if the current device is Tablet
113 - bool get isTablet => isSmallTablet || isLargeTablet; 130 + bool get isTablet => isSmallTablet;
  131 +
  132 + /// True if the width is smaller than 1200p
  133 + bool get isDesktopOrLess => width <= 1200;
  134 +
  135 + /// True if the width is higher than 1200p
  136 + bool get isDesktopOrWider => width >= 1200;
  137 +
  138 + /// same as [isDesktopOrLess]
  139 + bool get isDesktop => isDesktopOrLess;
114 140
115 /// Returns a specific value according to the screen size 141 /// Returns a specific value according to the screen size
116 /// if the device width is higher than or equal to 1200 return 142 /// if the device width is higher than or equal to 1200 return
@@ -119,23 +145,28 @@ extension ContextExtensionss on BuildContext { @@ -119,23 +145,28 @@ extension ContextExtensionss on BuildContext {
119 /// if the device width is less than 300 return [watch] value. 145 /// if the device width is less than 300 return [watch] value.
120 /// in other cases return [mobile] value. 146 /// in other cases return [mobile] value.
121 T responsiveValue<T>({ 147 T responsiveValue<T>({
  148 + T? watch,
122 T? mobile, 149 T? mobile,
123 T? tablet, 150 T? tablet,
124 T? desktop, 151 T? desktop,
125 - T? watch,  
126 }) { 152 }) {
127 - var deviceWidth = mediaQuerySize.shortestSide;  
128 - if (GetPlatform.isDesktop) {  
129 - deviceWidth = mediaQuerySize.width;  
130 - }  
131 - if (deviceWidth >= 1200 && desktop != null) {  
132 - return desktop;  
133 - } else if (deviceWidth >= 600 && tablet != null) {  
134 - return tablet;  
135 - } else if (deviceWidth < 300 && watch != null) {  
136 - return watch;  
137 - } else {  
138 - return mobile!;  
139 - } 153 + assert(
  154 + watch != null || mobile != null || tablet != null || desktop != null);
  155 +
  156 + var deviceWidth = mediaQuerySize.width;
  157 + //big screen width can display smaller sizes
  158 + final strictValues = [
  159 + if (deviceWidth >= 1200) desktop, //desktop is allowed
  160 + if (deviceWidth >= 600) tablet, //tablet is allowed
  161 + if (deviceWidth >= 300) mobile, //mobile is allowed
  162 + watch, //watch is allowed
  163 + ].whereType<T>();
  164 + final looseValues = [
  165 + watch,
  166 + mobile,
  167 + tablet,
  168 + desktop,
  169 + ].whereType<T>();
  170 + return strictValues.firstOrNull ?? looseValues.first;
140 } 171 }
141 } 172 }
@@ -34,16 +34,19 @@ void main() { @@ -34,16 +34,19 @@ void main() {
34 expect(isLandscape, context.isLandscape); 34 expect(isLandscape, context.isLandscape);
35 var mediaQueryShortestSide = mediaQuerySize.shortestSide; 35 var mediaQueryShortestSide = mediaQuerySize.shortestSide;
36 expect(mediaQueryShortestSide, context.mediaQueryShortestSide); 36 expect(mediaQueryShortestSide, context.mediaQueryShortestSide);
37 - var isLargeTablet = (mediaQueryShortestSide >= 720);  
38 - expect(isLargeTablet, context.isLargeTablet);  
39 - var isPhone = (mediaQueryShortestSide < 600);  
40 - expect(isPhone, context.isPhone); 37 + var width = mediaQuerySize.width;
  38 + expect(width, context.width);
  39 +
  40 + var isLargeTabletOrWider = (width >= 720);
  41 + expect(isLargeTabletOrWider, context.isLargeTabletOrWider);
  42 + var isPhoneOrLess = (width < 600);
  43 + expect(isPhoneOrLess, context.isPhoneOrLess);
41 var isPortrait = orientation == Orientation.portrait; 44 var isPortrait = orientation == Orientation.portrait;
42 expect(isPortrait, context.isPortrait); 45 expect(isPortrait, context.isPortrait);
43 - var isSmallTablet = (mediaQueryShortestSide >= 600);  
44 - expect(isSmallTablet, context.isSmallTablet);  
45 - var isTablet = isSmallTablet || isLargeTablet;  
46 - expect(isTablet, context.isTablet); 46 + var isSmallTabletOrWider = (width >= 600);
  47 + expect(isSmallTabletOrWider, context.isSmallTabletOrWider);
  48 + var isTablet = isSmallTabletOrWider || isLargeTabletOrWider;
  49 + expect(isTablet, context.isSmallTabletOrWider);
47 var mediaQueryPadding = mediaQuery.padding; 50 var mediaQueryPadding = mediaQuery.padding;
48 expect(mediaQueryPadding, context.mediaQueryPadding); 51 expect(mediaQueryPadding, context.mediaQueryPadding);
49 var mediaQueryViewInsets = mediaQuery.viewInsets; 52 var mediaQueryViewInsets = mediaQuery.viewInsets;
@@ -55,8 +58,7 @@ void main() { @@ -55,8 +58,7 @@ void main() {
55 expect(widthTransformer, context.widthTransformer()); 58 expect(widthTransformer, context.widthTransformer());
56 var ratio = heightTransformer / widthTransformer; 59 var ratio = heightTransformer / widthTransformer;
57 expect(ratio, context.ratio()); 60 expect(ratio, context.ratio());
58 - var width = mediaQuerySize.width;  
59 - expect(width, context.width); 61 +
60 var showNavbar = (width > 800); 62 var showNavbar = (width > 800);
61 expect(showNavbar, context.showNavbar); 63 expect(showNavbar, context.showNavbar);
62 var textScaleFactor = mediaQuery.textScaleFactor; 64 var textScaleFactor = mediaQuery.textScaleFactor;