Committed by
GitHub
Merge branch 'master' into master
Showing
65 changed files
with
1291 additions
and
1307 deletions
Too many changes to show.
To preserve performance only 65 of 65+ files are displayed.
No preview for this file type
1 | -## [4.5.1] - Big Update | 1 | +## [4.6.1] |
2 | +Fix GetConnect on Flutter web | ||
3 | + | ||
4 | +## [4.6.0] | ||
5 | +Add useInheritedMediaQuery to GetMaterialApp and GetCupertinoApp (@davidhole) | ||
6 | +Add Circular reveal Transition (@parmarravi) | ||
7 | +Add request to failed response (@heftekharm) | ||
8 | +Fix internationalization with only country code (@codercengiz) | ||
9 | +Add GetTickerProviderStateMixin when multiple AnimationController objects are used (@NatsuOnFire) | ||
10 | +Add the followRedirects and maxRedirects fields to the Request object (@wei53881) | ||
11 | +Fix to rx.trigger fires twice (@gslender) | ||
12 | +Add proxy setting support to GetConnect (@jtans) | ||
13 | +Fix markAsDirty used on permanent controllers (@zenalex) | ||
14 | +Update Korean readme (@dumbokim) | ||
15 | + | ||
16 | + | ||
17 | +## [4.5.1] | ||
2 | Fix Snackbar when it have action and icon the same time | 18 | Fix Snackbar when it have action and icon the same time |
3 | 19 | ||
4 | ## [4.5.0] - Big Update | 20 | ## [4.5.0] - Big Update |
5 | -To have a context-free, page-agnostic snackbar, we used OverlayRoute to display a partial route. | 21 | +To have a page-agnostic snackbar, we used OverlayRoute to display a partial route. |
6 | However this had several problems: | 22 | However this had several problems: |
7 | 23 | ||
8 | 1: There was no possibility to close the page without closing the snackbar | 24 | 1: There was no possibility to close the page without closing the snackbar |
@@ -37,6 +37,17 @@ _语言: 中文, [英文](README.md), [越南文](README-vi.md), [印度尼西 | @@ -37,6 +37,17 @@ _语言: 中文, [英文](README.md), [越南文](README-vi.md), [印度尼西 | ||
37 | - [改变语言](#改变语言) | 37 | - [改变语言](#改变语言) |
38 | - [系统语言](#系统语言) | 38 | - [系统语言](#系统语言) |
39 | - [改变主题](#改变主题) | 39 | - [改变主题](#改变主题) |
40 | + - [GetConnect](#getconnect) | ||
41 | + - [默认配置](#默认配置) | ||
42 | + - [自定义配置](#自定义配置) | ||
43 | + - [GetPage 中间件](#getpage-中间件) | ||
44 | + - [优先级](#优先级) | ||
45 | + - [Redirect](#redirect) | ||
46 | + - [onPageCalled](#onpagecalled) | ||
47 | + - [OnBindingsStart](#onbindingsstart) | ||
48 | + - [OnPageBuildStart](#onpagebuildstart) | ||
49 | + - [OnPageBuilt](#onpagebuilt) | ||
50 | + - [OnPageDispose](#onpagedispose) | ||
40 | - [其他高级API](#其他高级api) | 51 | - [其他高级API](#其他高级api) |
41 | - [可选的全局设置和手动配置](#可选的全局设置和手动配置) | 52 | - [可选的全局设置和手动配置](#可选的全局设置和手动配置) |
42 | - [局部状态组件](#局部状态组件) | 53 | - [局部状态组件](#局部状态组件) |
@@ -394,6 +405,163 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); | @@ -394,6 +405,163 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); | ||
394 | 405 | ||
395 | 当`.darkmode`被激活时,它将切换到light主题,当light主题被激活时,它将切换到dark主题。 | 406 | 当`.darkmode`被激活时,它将切换到light主题,当light主题被激活时,它将切换到dark主题。 |
396 | 407 | ||
408 | +## GetConnect | ||
409 | + | ||
410 | +GetConnect可以便捷的通过http或websockets进行前后台通信。 | ||
411 | + | ||
412 | +### 默认配置 | ||
413 | + | ||
414 | +你能轻松的通过extend GetConnect就能使用GET/POST/PUT/DELETE/SOCKET方法与你的Rest API或websockets通信。 | ||
415 | + | ||
416 | +```dart | ||
417 | +class UserProvider extends GetConnect { | ||
418 | + // Get request | ||
419 | + Future<Response> getUser(int id) => get('http://youapi/users/$id'); | ||
420 | + // Post request | ||
421 | + Future<Response> postUser(Map data) => post('http://youapi/users', body: data); | ||
422 | + // Post request with File | ||
423 | + Future<Response<CasesModel>> postCases(List<int> image) { | ||
424 | + final form = FormData({ | ||
425 | + 'file': MultipartFile(image, filename: 'avatar.png'), | ||
426 | + 'otherFile': MultipartFile(image, filename: 'cover.png'), | ||
427 | + }); | ||
428 | + return post('http://youapi/users/upload', form); | ||
429 | + } | ||
430 | + | ||
431 | + GetSocket userMessages() { | ||
432 | + return socket('https://yourapi/users/socket'); | ||
433 | + } | ||
434 | +} | ||
435 | +``` | ||
436 | + | ||
437 | +### 自定义配置 | ||
438 | + | ||
439 | +GetConnect具有多种自定义配置。你可以配置base Url,配置响应,配置请求,添加权限验证,甚至是尝试认证的次数,除此之外,还可以定义一个标准的解码器,该解码器将把您的所有请求转换为您的模型,而不需要任何额外的配置。 | ||
440 | + | ||
441 | +```dart | ||
442 | +class HomeProvider extends GetConnect { | ||
443 | + @override | ||
444 | + void onInit() { | ||
445 | + // All request will pass to jsonEncode so CasesModel.fromJson() | ||
446 | + httpClient.defaultDecoder = CasesModel.fromJson; | ||
447 | + httpClient.baseUrl = 'https://api.covid19api.com'; | ||
448 | + // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to | ||
449 | + // Http and websockets if used with no [httpClient] instance | ||
450 | + | ||
451 | + // It's will attach 'apikey' property on header from all requests | ||
452 | + httpClient.addRequestModifier((request) { | ||
453 | + request.headers['apikey'] = '12345678'; | ||
454 | + return request; | ||
455 | + }); | ||
456 | + | ||
457 | + // Even if the server sends data from the country "Brazil", | ||
458 | + // it will never be displayed to users, because you remove | ||
459 | + // that data from the response, even before the response is delivered | ||
460 | + httpClient.addResponseModifier<CasesModel>((request, response) { | ||
461 | + CasesModel model = response.body; | ||
462 | + if (model.countries.contains('Brazil')) { | ||
463 | + model.countries.remove('Brazilll'); | ||
464 | + } | ||
465 | + }); | ||
466 | + | ||
467 | + httpClient.addAuthenticator((request) async { | ||
468 | + final response = await get("http://yourapi/token"); | ||
469 | + final token = response.body['token']; | ||
470 | + // Set the header | ||
471 | + request.headers['Authorization'] = "$token"; | ||
472 | + return request; | ||
473 | + }); | ||
474 | + | ||
475 | + //Autenticator will be called 3 times if HttpStatus is | ||
476 | + //HttpStatus.unauthorized | ||
477 | + httpClient.maxAuthRetries = 3; | ||
478 | + } | ||
479 | + } | ||
480 | + | ||
481 | + @override | ||
482 | + Future<Response<CasesModel>> getCases(String path) => get(path); | ||
483 | +} | ||
484 | +``` | ||
485 | + | ||
486 | +## GetPage 中间件 | ||
487 | + | ||
488 | +GetPage现在有个新的参数可以把列表中的Get中间件按指定顺序执行。 | ||
489 | + | ||
490 | +**注意**: 当GetPage有中间件时,所有的子page会自动有相同的中间件。 | ||
491 | + | ||
492 | +### 优先级 | ||
493 | + | ||
494 | +设置中间件的优先级定义Get中间件的执行顺序。 | ||
495 | + | ||
496 | +```dart | ||
497 | +final middlewares = [ | ||
498 | + GetMiddleware(priority: 2), | ||
499 | + GetMiddleware(priority: 5), | ||
500 | + GetMiddleware(priority: 4), | ||
501 | + GetMiddleware(priority: -8), | ||
502 | +]; | ||
503 | +``` | ||
504 | + | ||
505 | +这些中间件会按这个顺序执行 **-8 => 2 => 4 => 5** | ||
506 | + | ||
507 | +### Redirect | ||
508 | + | ||
509 | +当被调用路由的页面被搜索时,这个函数将被调用。它将RouteSettings作为重定向的结果。或者给它null,就没有重定向了。 | ||
510 | + | ||
511 | +```dart | ||
512 | +RouteSettings redirect(String route) { | ||
513 | + final authService = Get.find<AuthService>(); | ||
514 | + return authService.authed.value ? null : RouteSettings(name: '/login') | ||
515 | +} | ||
516 | +``` | ||
517 | + | ||
518 | +### onPageCalled | ||
519 | + | ||
520 | +在调用页面时,创建任何东西之前,这个函数会先被调用。 | ||
521 | +您可以使用它来更改页面的某些内容或给它一个新页面。 | ||
522 | + | ||
523 | +```dart | ||
524 | +GetPage onPageCalled(GetPage page) { | ||
525 | + final authService = Get.find<AuthService>(); | ||
526 | + return page.copyWith(title: 'Welcome ${authService.UserName}'); | ||
527 | +} | ||
528 | +``` | ||
529 | + | ||
530 | +### OnBindingsStart | ||
531 | + | ||
532 | +这个函数将在绑定初始化之前被调用。 | ||
533 | +在这里,您可以更改此页面的绑定。 | ||
534 | + | ||
535 | +```dart | ||
536 | +List<Bindings> onBindingsStart(List<Bindings> bindings) { | ||
537 | + final authService = Get.find<AuthService>(); | ||
538 | + if (authService.isAdmin) { | ||
539 | + bindings.add(AdminBinding()); | ||
540 | + } | ||
541 | + return bindings; | ||
542 | +} | ||
543 | +``` | ||
544 | + | ||
545 | +### OnPageBuildStart | ||
546 | + | ||
547 | +这个函数将在绑定初始化之后被调用。 | ||
548 | +在这里,您可以在创建绑定之后和创建页面widget之前执行一些操作。 | ||
549 | + | ||
550 | +```dart | ||
551 | +GetPageBuilder onPageBuildStart(GetPageBuilder page) { | ||
552 | + print('bindings are ready'); | ||
553 | + return page; | ||
554 | +} | ||
555 | +``` | ||
556 | + | ||
557 | +### OnPageBuilt | ||
558 | + | ||
559 | +这个函数将在GetPage.page调用后被调用,并给出函数的结果,并获取将要显示的widget。 | ||
560 | + | ||
561 | +### OnPageDispose | ||
562 | + | ||
563 | +这个函数将在处理完页面的所有相关对象(Controllers, views, ...)之后被调用。 | ||
564 | + | ||
397 | ## 其他高级API | 565 | ## 其他高级API |
398 | 566 | ||
399 | ```dart | 567 | ```dart |
@@ -59,11 +59,11 @@ var name = 'Jonatas Borges'.obs; | @@ -59,11 +59,11 @@ var name = 'Jonatas Borges'.obs; | ||
59 | 59 | ||
60 | 就这么简单! | 60 | 就这么简单! |
61 | 61 | ||
62 | -我们把这个reactive-".obs"(ervables)变量称为_Rx_。 | 62 | +我们把这个reactive-".obs"(ervables)变量称为 _Rx_ 。 |
63 | 63 | ||
64 | 我们做了什么?我们创建了一个 "Stream "的 "String",分配了初始值 "Jonatas Borges",我们通知所有使用 "Jonatas Borges "的widgets,它们现在 "属于 "这个变量,当_Rx_的值发生变化时,它们也要随之改变。 | 64 | 我们做了什么?我们创建了一个 "Stream "的 "String",分配了初始值 "Jonatas Borges",我们通知所有使用 "Jonatas Borges "的widgets,它们现在 "属于 "这个变量,当_Rx_的值发生变化时,它们也要随之改变。 |
65 | 65 | ||
66 | -这就是GetX**的**魔力,这要归功于Dart的能力。 | 66 | +这就是GetX **的** 魔力,这要归功于Dart的能力。 |
67 | 67 | ||
68 | 但是,我们知道,一个`Widget`只有在函数里面才能改变,因为静态类没有 "自动改变 "的能力。 | 68 | 但是,我们知道,一个`Widget`只有在函数里面才能改变,因为静态类没有 "自动改变 "的能力。 |
69 | 69 | ||
@@ -80,15 +80,15 @@ var name = 'Jonatas Borges'.obs; | @@ -80,15 +80,15 @@ var name = 'Jonatas Borges'.obs; | ||
80 | Obx (() => Text (controller.name)); | 80 | Obx (() => Text (controller.name)); |
81 | ``` | 81 | ``` |
82 | 82 | ||
83 | -_你只需记住 `Obx(()=>` | 83 | +你只需记住 `Obx(()=>` |
84 | 84 | ||
85 | -你只需将Widget通过一个箭头函数传递给 `Obx()`(_Rx_的 "观察者")。 | 85 | +你只需将Widget通过一个箭头函数传递给 `Obx()`( _Rx_ 的 "观察者")。 |
86 | 86 | ||
87 | `Obx`是相当聪明的,只有当`controller.name`的值发生变化时才会改变。 | 87 | `Obx`是相当聪明的,只有当`controller.name`的值发生变化时才会改变。 |
88 | 88 | ||
89 | 如果`name`是`"John"`,你把它改成了`"John"`(`name.value="John"`),因为它和之前的`value`是一样的,所以界面上不会有任何变化,而`Obx`为了节省资源,会直接忽略新的值,不重建Widget。**这是不是很神奇**? | 89 | 如果`name`是`"John"`,你把它改成了`"John"`(`name.value="John"`),因为它和之前的`value`是一样的,所以界面上不会有任何变化,而`Obx`为了节省资源,会直接忽略新的值,不重建Widget。**这是不是很神奇**? |
90 | 90 | ||
91 | -> 那么,如果我在一个`Obx`里有5个_Rx_(可观察的)变量呢? | 91 | +> 那么,如果我在一个`Obx`里有5个 _Rx_ (可观察的)变量呢? |
92 | 92 | ||
93 | 当其中**任何**一个变量发生变化时,它就会更新。 | 93 | 当其中**任何**一个变量发生变化时,它就会更新。 |
94 | 94 | ||
@@ -96,7 +96,7 @@ _你只需记住 `Obx(()=>` | @@ -96,7 +96,7 @@ _你只需记住 `Obx(()=>` | ||
96 | 96 | ||
97 | 不会,只会更新使用那个 _Rx_ 变量的**特定 Widget**。 | 97 | 不会,只会更新使用那个 _Rx_ 变量的**特定 Widget**。 |
98 | 98 | ||
99 | -所以,只有当_Rx_变量的值发生变化时,**GetX**才会更新界面。 | 99 | +所以,只有当 _Rx_ 变量的值发生变化时,**GetX**才会更新界面。 |
100 | 100 | ||
101 | ``` | 101 | ``` |
102 | final isOpen = false.obs; | 102 | final isOpen = false.obs; |
@@ -114,13 +114,13 @@ void onButtonTap() => isOpen.value=false; | @@ -114,13 +114,13 @@ void onButtonTap() => isOpen.value=false; | ||
114 | 114 | ||
115 | 如果你需要一个**强大的**状态管理器,用**GetX**是不会错的。 | 115 | 如果你需要一个**强大的**状态管理器,用**GetX**是不会错的。 |
116 | 116 | ||
117 | -它不能和变量一起工作,除了__flows__,它里面的东西本质都是`Streams`。 | ||
118 | -你可以将_rxDart_与它结合使用,因为所有的东西都是`Streams`。 | ||
119 | -你可以监听每个"_Rx_变量 "的 "事件"。 | 117 | +它不能和变量一起工作,除了 __flows__ ,它里面的东西本质都是`Streams`。 |
118 | +你可以将 _rxDart_ 与它结合使用,因为所有的东西都是`Streams`。 | ||
119 | +你可以监听每个" _Rx_ 变量 "的 "事件"。 | ||
120 | 因为里面的所有东西都是 "Streams"。 | 120 | 因为里面的所有东西都是 "Streams"。 |
121 | 121 | ||
122 | -这实际上是一种_BLoC_方法,比_MobX_更容易,而且没有代码生成器或装饰。 | ||
123 | -你可以把**任何东西**变成一个_"Observable"_,只需要在它末尾加上`.obs`。 | 122 | +这实际上是一种 _BLoC_ 方法,比 _MobX_ 更容易,而且没有代码生成器或装饰。 |
123 | +你可以把**任何东西**变成一个 _"Observable"_ ,只需要在它末尾加上`.obs`。 | ||
124 | 124 | ||
125 | ### 最高性能 | 125 | ### 最高性能 |
126 | 126 | ||
@@ -129,8 +129,8 @@ void onButtonTap() => isOpen.value=false; | @@ -129,8 +129,8 @@ void onButtonTap() => isOpen.value=false; | ||
129 | 如果你的应用程序中遇到错误,并发送重复的状态变更,**GetX**将确保它不会崩溃。 | 129 | 如果你的应用程序中遇到错误,并发送重复的状态变更,**GetX**将确保它不会崩溃。 |
130 | 130 | ||
131 | 使用**GetX**,只有当`value`改变时,状态才会改变。 | 131 | 使用**GetX**,只有当`value`改变时,状态才会改变。 |
132 | -这就是**GetX**,和使用MobX_的_`computed`的主要区别。 | ||
133 | -当加入两个__observable__,其中一个发生变化时,该_observable_的监听器也会发生变化。 | 132 | +这就是**GetX**,和使用MobX _的_ `computed`的主要区别。 |
133 | +当加入两个 __observable__ ,其中一个发生变化时,该 _observable_ 的监听器也会发生变化。 | ||
134 | 134 | ||
135 | 使用**GetX**,如果你连接了两个变量,`GetX()`(类似于`Observer()`)只有在它的状态真正变化时才会重建。 | 135 | 使用**GetX**,如果你连接了两个变量,`GetX()`(类似于`Observer()`)只有在它的状态真正变化时才会重建。 |
136 | 136 | ||
@@ -183,13 +183,13 @@ final user = User().obs; | @@ -183,13 +183,13 @@ final user = User().obs; | ||
183 | 183 | ||
184 | ##### 有一个反应的状态,很容易。 | 184 | ##### 有一个反应的状态,很容易。 |
185 | 185 | ||
186 | -我们知道,_Dart_现在正朝着_null safety_的方向发展。 | ||
187 | -为了做好准备,从现在开始,你应该总是用一个**初始值**来开始你的_Rx_变量。 | 186 | +我们知道, _Dart_ 现在正朝着 _null safety_ 的方向发展。 |
187 | +为了做好准备,从现在开始,你应该总是用一个**初始值**来开始你的 _Rx_ 变量。 | ||
188 | 188 | ||
189 | -> 用**GetX**将一个变量转化为一个_observable_ + _initial value_是最简单,也是最实用的方法。 | 189 | +> 用**GetX**将一个变量转化为一个 _observable_ + _initial value_ 是最简单,也是最实用的方法。 |
190 | 190 | ||
191 | 你只需在变量的末尾添加一个"`.obs`",即可把它变成可观察的变量, | 191 | 你只需在变量的末尾添加一个"`.obs`",即可把它变成可观察的变量, |
192 | -然后它的`.value`就是_初始值_)。 | 192 | +然后它的`.value`就是 _初始值_ )。 |
193 | 193 | ||
194 | 194 | ||
195 | ### 使用视图中的值 | 195 | ### 使用视图中的值 |
@@ -411,17 +411,17 @@ interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1)); | @@ -411,17 +411,17 @@ interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1)); | ||
411 | 所有worker都会返回一个`Worker`实例,你可以用它来取消(通过`dispose()`)worker。 | 411 | 所有worker都会返回一个`Worker`实例,你可以用它来取消(通过`dispose()`)worker。 |
412 | 412 | ||
413 | - **`ever`** | 413 | - **`ever`** |
414 | - 每当_Rx_变量发出一个新的值时,就会被调用。 | 414 | + 每当 _Rx_ 变量发出一个新的值时,就会被调用。 |
415 | 415 | ||
416 | - **`everAll`** | 416 | - **`everAll`** |
417 | - 和 "ever "很像,但它需要一个_Rx_值的 "List",每次它的变量被改变时都会被调用。就是这样。 | 417 | + 和 "ever "很像,但它需要一个 _Rx_ 值的 "List",每次它的变量被改变时都会被调用。就是这样。 |
418 | 418 | ||
419 | 419 | ||
420 | - **`once`** | 420 | - **`once`** |
421 | 'once'只在变量第一次被改变时被调用。 | 421 | 'once'只在变量第一次被改变时被调用。 |
422 | 422 | ||
423 | - **`debounce`** | 423 | - **`debounce`** |
424 | -debounce'在搜索函数中非常有用,你只希望API在用户完成输入时被调用。如果用户输入 "Jonny",你将在API中进行5次搜索,分别是字母J、o、n、n和y。使用Get不会发生这种情况,因为你将有一个 "debounce "Worker,它只会在输入结束时触发。 | 424 | +'debounce'在搜索函数中非常有用,你只希望API在用户完成输入时被调用。如果用户输入 "Jonny",你将在API中进行5次搜索,分别是字母J、o、n、n和y。使用Get不会发生这种情况,因为你将有一个 "debounce "Worker,它只会在输入结束时触发。 |
425 | 425 | ||
426 | - **`interval`** | 426 | - **`interval`** |
427 | 'interval'与debouce不同,debouce如果用户在1秒内对一个变量进行了1000次修改,他将在规定的计时器(默认为800毫秒)后只发送最后一次修改。Interval则会忽略规定时间内的所有用户操作。如果你发送事件1分钟,每秒1000个,那么当用户停止DDOS事件时,debounce将只发送最后一个事件。建议这样做是为了避免滥用,在用户可以快速点击某样东西并获得一些好处的功能中(想象一下,用户点击某样东西可以赚取硬币,如果他在同一分钟内点击300次,他就会有300个硬币,使用间隔,你可以设置时间范围为3秒,无论是点击300次或100万次,1分钟内他最多获得20个硬币)。debounce适用于防DDOS,适用于搜索等功能,每次改变onChange都会调用你的api进行查询。Debounce会等待用户停止输入名称,进行请求。如果在上面提到的投币场景中使用它,用户只会赢得1个硬币,因为只有当用户 "暂停 "到既定时间时,它才会被执行。 | 427 | 'interval'与debouce不同,debouce如果用户在1秒内对一个变量进行了1000次修改,他将在规定的计时器(默认为800毫秒)后只发送最后一次修改。Interval则会忽略规定时间内的所有用户操作。如果你发送事件1分钟,每秒1000个,那么当用户停止DDOS事件时,debounce将只发送最后一个事件。建议这样做是为了避免滥用,在用户可以快速点击某样东西并获得一些好处的功能中(想象一下,用户点击某样东西可以赚取硬币,如果他在同一分钟内点击300次,他就会有300个硬币,使用间隔,你可以设置时间范围为3秒,无论是点击300次或100万次,1分钟内他最多获得20个硬币)。debounce适用于防DDOS,适用于搜索等功能,每次改变onChange都会调用你的api进行查询。Debounce会等待用户停止输入名称,进行请求。如果在上面提到的投币场景中使用它,用户只会赢得1个硬币,因为只有当用户 "暂停 "到既定时间时,它才会被执行。 |
1 | -import 'package:flutter/foundation.dart'; | ||
2 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
3 | import 'package:get/get.dart'; | 2 | import 'package:get/get.dart'; |
4 | 3 | ||
@@ -15,11 +14,11 @@ class MyApp extends StatelessWidget { | @@ -15,11 +14,11 @@ class MyApp extends StatelessWidget { | ||
15 | 14 | ||
16 | @override | 15 | @override |
17 | Widget build(BuildContext context) { | 16 | Widget build(BuildContext context) { |
18 | - return GetMaterialApp.router( | 17 | + return GetMaterialApp( |
19 | debugShowCheckedModeBanner: false, | 18 | debugShowCheckedModeBanner: false, |
20 | enableLog: true, | 19 | enableLog: true, |
21 | logWriterCallback: Logger.write, | 20 | logWriterCallback: Logger.write, |
22 | - // initialRoute: AppPages.INITIAL, | 21 | + initialRoute: AppPages.INITIAL, |
23 | getPages: AppPages.routes, | 22 | getPages: AppPages.routes, |
24 | locale: TranslationService.locale, | 23 | locale: TranslationService.locale, |
25 | fallbackLocale: TranslationService.fallbackLocale, | 24 | fallbackLocale: TranslationService.fallbackLocale, |
1 | import 'package:get/get.dart'; | 1 | import 'package:get/get.dart'; |
2 | -import '../data/home_api_provider.dart'; | ||
3 | 2 | ||
3 | +import '../data/home_api_provider.dart'; | ||
4 | import '../data/home_repository.dart'; | 4 | import '../data/home_repository.dart'; |
5 | import '../domain/adapters/repository_adapter.dart'; | 5 | import '../domain/adapters/repository_adapter.dart'; |
6 | import '../presentation/controllers/home_controller.dart'; | 6 | import '../presentation/controllers/home_controller.dart'; |
1 | import 'package:get/get.dart'; | 1 | import 'package:get/get.dart'; |
2 | + | ||
2 | import '../domain/entity/cases_model.dart'; | 3 | import '../domain/entity/cases_model.dart'; |
3 | 4 | ||
4 | // ignore: one_member_abstracts | 5 | // ignore: one_member_abstracts |
@@ -12,6 +13,7 @@ class HomeProvider extends GetConnect implements IHomeProvider { | @@ -12,6 +13,7 @@ class HomeProvider extends GetConnect implements IHomeProvider { | ||
12 | httpClient.defaultDecoder = | 13 | httpClient.defaultDecoder = |
13 | (val) => CasesModel.fromJson(val as Map<String, dynamic>); | 14 | (val) => CasesModel.fromJson(val as Map<String, dynamic>); |
14 | httpClient.baseUrl = 'https://api.covid19api.com'; | 15 | httpClient.baseUrl = 'https://api.covid19api.com'; |
16 | + super.onInit(); | ||
15 | } | 17 | } |
16 | 18 | ||
17 | @override | 19 | @override |
@@ -3,7 +3,7 @@ import 'package:get/get.dart'; | @@ -3,7 +3,7 @@ import 'package:get/get.dart'; | ||
3 | import '../../domain/adapters/repository_adapter.dart'; | 3 | import '../../domain/adapters/repository_adapter.dart'; |
4 | import '../../domain/entity/cases_model.dart'; | 4 | import '../../domain/entity/cases_model.dart'; |
5 | 5 | ||
6 | -class HomeController extends SuperController<CasesModel> { | 6 | +class HomeController extends StateController<CasesModel> { |
7 | HomeController({required this.homeRepository}); | 7 | HomeController({required this.homeRepository}); |
8 | 8 | ||
9 | final IHomeRepository homeRepository; | 9 | final IHomeRepository homeRepository; |
@@ -11,74 +11,12 @@ class HomeController extends SuperController<CasesModel> { | @@ -11,74 +11,12 @@ class HomeController extends SuperController<CasesModel> { | ||
11 | @override | 11 | @override |
12 | void onInit() { | 12 | void onInit() { |
13 | super.onInit(); | 13 | super.onInit(); |
14 | - | ||
15 | //Loading, Success, Error handle with 1 line of code | 14 | //Loading, Success, Error handle with 1 line of code |
16 | - append(() => homeRepository.getCases); | 15 | + futurize(() => homeRepository.getCases); |
17 | } | 16 | } |
18 | 17 | ||
19 | Country getCountryById(String id) { | 18 | Country getCountryById(String id) { |
20 | final index = int.tryParse(id); | 19 | final index = int.tryParse(id); |
21 | - if (index != null) { | ||
22 | - return state!.countries[index]; | ||
23 | - } | ||
24 | - | ||
25 | - return state!.countries.first; | ||
26 | - } | ||
27 | - | ||
28 | - @override | ||
29 | - void onReady() { | ||
30 | - print('The build method is done. ' | ||
31 | - 'Your controller is ready to call dialogs and snackbars'); | ||
32 | - super.onReady(); | ||
33 | - } | ||
34 | - | ||
35 | - @override | ||
36 | - void onClose() { | ||
37 | - print('onClose called'); | ||
38 | - super.onClose(); | ||
39 | - } | ||
40 | - | ||
41 | - @override | ||
42 | - void didChangeMetrics() { | ||
43 | - print('the window size did change'); | ||
44 | - super.didChangeMetrics(); | ||
45 | - } | ||
46 | - | ||
47 | - @override | ||
48 | - void didChangePlatformBrightness() { | ||
49 | - print('platform change ThemeMode'); | ||
50 | - super.didChangePlatformBrightness(); | ||
51 | - } | ||
52 | - | ||
53 | - @override | ||
54 | - Future<bool> didPushRoute(String route) { | ||
55 | - print('the route $route will be open'); | ||
56 | - return super.didPushRoute(route); | ||
57 | - } | ||
58 | - | ||
59 | - @override | ||
60 | - Future<bool> didPopRoute() { | ||
61 | - print('the current route will be closed'); | ||
62 | - return super.didPopRoute(); | ||
63 | - } | ||
64 | - | ||
65 | - @override | ||
66 | - void onDetached() { | ||
67 | - print('onDetached called'); | ||
68 | - } | ||
69 | - | ||
70 | - @override | ||
71 | - void onInactive() { | ||
72 | - print('onInative called'); | ||
73 | - } | ||
74 | - | ||
75 | - @override | ||
76 | - void onPaused() { | ||
77 | - print('onPaused called'); | ||
78 | - } | ||
79 | - | ||
80 | - @override | ||
81 | - void onResumed() { | ||
82 | - print('onResumed called'); | 20 | + return index != null ? state.countries[index] : state.countries.first; |
83 | } | 21 | } |
84 | } | 22 | } |
@@ -6,6 +6,7 @@ import 'package:get/get.dart'; | @@ -6,6 +6,7 @@ import 'package:get/get.dart'; | ||
6 | import '../controllers/home_controller.dart'; | 6 | import '../controllers/home_controller.dart'; |
7 | 7 | ||
8 | class CountryView extends GetView<HomeController> { | 8 | class CountryView extends GetView<HomeController> { |
9 | + const CountryView({Key? key}) : super(key: key); | ||
9 | @override | 10 | @override |
10 | Widget build(BuildContext context) { | 11 | Widget build(BuildContext context) { |
11 | return Container( | 12 | return Container( |
@@ -28,14 +29,15 @@ class CountryView extends GetView<HomeController> { | @@ -28,14 +29,15 @@ class CountryView extends GetView<HomeController> { | ||
28 | ), | 29 | ), |
29 | body: Center( | 30 | body: Center( |
30 | child: ListView.builder( | 31 | child: ListView.builder( |
31 | - itemCount: controller.state!.countries.length, | 32 | + itemCount: controller.state.countries.length, |
32 | itemBuilder: (context, index) { | 33 | itemBuilder: (context, index) { |
33 | - final country = controller.state!.countries[index]; | 34 | + final country = controller.state.countries[index]; |
34 | return ListTile( | 35 | return ListTile( |
35 | - onTap: () { | 36 | + onTap: () async { |
36 | //Get.rootDelegate.toNamed('/home/country'); | 37 | //Get.rootDelegate.toNamed('/home/country'); |
37 | - Get.rootDelegate | ||
38 | - .toNamed('/home/country/details?id=$index'); | 38 | + final data = await Get.toNamed( |
39 | + '/home/country/details?id=$index'); | ||
40 | + print(data); | ||
39 | }, | 41 | }, |
40 | trailing: CircleAvatar( | 42 | trailing: CircleAvatar( |
41 | backgroundImage: NetworkImage( | 43 | backgroundImage: NetworkImage( |
@@ -2,12 +2,14 @@ import 'dart:ui'; | @@ -2,12 +2,14 @@ import 'dart:ui'; | ||
2 | 2 | ||
3 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
4 | import 'package:get/get.dart'; | 4 | import 'package:get/get.dart'; |
5 | + | ||
5 | import '../controllers/home_controller.dart'; | 6 | import '../controllers/home_controller.dart'; |
6 | 7 | ||
7 | class DetailsView extends GetView<HomeController> { | 8 | class DetailsView extends GetView<HomeController> { |
9 | + const DetailsView({Key? key}) : super(key: key); | ||
8 | @override | 10 | @override |
9 | Widget build(BuildContext context) { | 11 | Widget build(BuildContext context) { |
10 | - final parameter = Get.rootDelegate.parameters; | 12 | + final parameter = context.params; //Get.parameters; |
11 | final country = controller.getCountryById(parameter['id'] ?? ''); | 13 | final country = controller.getCountryById(parameter['id'] ?? ''); |
12 | return Container( | 14 | return Container( |
13 | decoration: BoxDecoration( | 15 | decoration: BoxDecoration( |
@@ -76,6 +78,11 @@ class DetailsView extends GetView<HomeController> { | @@ -76,6 +78,11 @@ class DetailsView extends GetView<HomeController> { | ||
76 | '${country.totalRecovered}', | 78 | '${country.totalRecovered}', |
77 | style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold), | 79 | style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold), |
78 | ), | 80 | ), |
81 | + TextButton( | ||
82 | + onPressed: () { | ||
83 | + Get.back(result: 'djsoidjsoidj'); | ||
84 | + }, | ||
85 | + child: Text('back')) | ||
79 | ], | 86 | ], |
80 | )), | 87 | )), |
81 | ), | 88 | ), |
1 | -import 'dart:ui'; | ||
2 | - | ||
3 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
4 | import 'package:get/get.dart'; | 2 | import 'package:get/get.dart'; |
5 | 3 | ||
6 | import '../controllers/home_controller.dart'; | 4 | import '../controllers/home_controller.dart'; |
7 | 5 | ||
8 | class HomeView extends GetView<HomeController> { | 6 | class HomeView extends GetView<HomeController> { |
7 | + const HomeView({Key? key}) : super(key: key); | ||
8 | + | ||
9 | @override | 9 | @override |
10 | Widget build(BuildContext context) { | 10 | Widget build(BuildContext context) { |
11 | return Container( | 11 | return Container( |
@@ -77,9 +77,8 @@ class HomeView extends GetView<HomeController> { | @@ -77,9 +77,8 @@ class HomeView extends GetView<HomeController> { | ||
77 | shape: StadiumBorder(), | 77 | shape: StadiumBorder(), |
78 | ), | 78 | ), |
79 | onPressed: () async { | 79 | onPressed: () async { |
80 | - final data = | ||
81 | - await Get.rootDelegate.toNamed('/home/country'); | ||
82 | - print('DATA: $data'); | 80 | + //await Navigation Get.rootDelegate.toNamed('/home/country'); |
81 | + Get.toNamed('/home/country'); | ||
83 | }, | 82 | }, |
84 | child: Text( | 83 | child: Text( |
85 | 'fetch_country'.tr, | 84 | 'fetch_country'.tr, |
@@ -15,7 +15,7 @@ class AppPages { | @@ -15,7 +15,7 @@ class AppPages { | ||
15 | GetPage( | 15 | GetPage( |
16 | name: Routes.HOME, | 16 | name: Routes.HOME, |
17 | page: () => HomeView(), | 17 | page: () => HomeView(), |
18 | - binding: HomeBinding(), | 18 | + bindings: [HomeBinding()], |
19 | children: [ | 19 | children: [ |
20 | GetPage( | 20 | GetPage( |
21 | name: Routes.COUNTRY, | 21 | name: Routes.COUNTRY, |
@@ -27,6 +27,7 @@ class AppPages { | @@ -27,6 +27,7 @@ class AppPages { | ||
27 | ), | 27 | ), |
28 | ], | 28 | ], |
29 | ), | 29 | ), |
30 | - ]), | 30 | + ], |
31 | + ), | ||
31 | ]; | 32 | ]; |
32 | } | 33 | } |
@@ -4,4 +4,8 @@ abstract class Routes { | @@ -4,4 +4,8 @@ abstract class Routes { | ||
4 | static const HOME = '/home'; | 4 | static const HOME = '/home'; |
5 | static const COUNTRY = '/country'; | 5 | static const COUNTRY = '/country'; |
6 | static const DETAILS = '/details'; | 6 | static const DETAILS = '/details'; |
7 | + | ||
8 | + static const DASHBOARD = '/dashboard'; | ||
9 | + static const PROFILE = '/profile'; | ||
10 | + static const PRODUCTS = '/products'; | ||
7 | } | 11 | } |
1 | -class Logger { | 1 | +mixin Logger { |
2 | // Sample of abstract logging function | 2 | // Sample of abstract logging function |
3 | static void write(String text, {bool isError = false}) { | 3 | static void write(String text, {bool isError = false}) { |
4 | Future.microtask(() => print('** $text. isError: [$isError]')); | 4 | Future.microtask(() => print('** $text. isError: [$isError]')); |
@@ -20,6 +20,10 @@ version: 1.0.0+1 | @@ -20,6 +20,10 @@ version: 1.0.0+1 | ||
20 | environment: | 20 | environment: |
21 | sdk: ">=2.12.0 <3.0.0" | 21 | sdk: ">=2.12.0 <3.0.0" |
22 | 22 | ||
23 | +dependency_overrides: | ||
24 | + get: | ||
25 | + path: ../ | ||
26 | + | ||
23 | dependencies: | 27 | dependencies: |
24 | flutter: | 28 | flutter: |
25 | sdk: flutter | 29 | sdk: flutter |
@@ -33,6 +37,7 @@ dependencies: | @@ -33,6 +37,7 @@ dependencies: | ||
33 | dev_dependencies: | 37 | dev_dependencies: |
34 | flutter_test: | 38 | flutter_test: |
35 | sdk: flutter | 39 | sdk: flutter |
40 | + get_test: 4.0.1 | ||
36 | 41 | ||
37 | # For information on the generic Dart part of this file, see the | 42 | # For information on the generic Dart part of this file, see the |
38 | # following page: https://dart.dev/tools/pub/pubspec | 43 | # following page: https://dart.dev/tools/pub/pubspec |
1 | import 'dart:io'; | 1 | import 'dart:io'; |
2 | -import 'dart:math'; | 2 | + |
3 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
4 | import 'package:flutter_test/flutter_test.dart'; | 4 | import 'package:flutter_test/flutter_test.dart'; |
5 | import 'package:get/get.dart'; | 5 | import 'package:get/get.dart'; |
@@ -7,16 +7,16 @@ import 'package:get/get.dart'; | @@ -7,16 +7,16 @@ import 'package:get/get.dart'; | ||
7 | // import 'package:get_test/get_test.dart'; | 7 | // import 'package:get_test/get_test.dart'; |
8 | import 'package:matcher/matcher.dart' as m; | 8 | import 'package:matcher/matcher.dart' as m; |
9 | 9 | ||
10 | + | ||
10 | import '../lib/pages/home/domain/adapters/repository_adapter.dart'; | 11 | import '../lib/pages/home/domain/adapters/repository_adapter.dart'; |
11 | import '../lib/pages/home/domain/entity/cases_model.dart'; | 12 | import '../lib/pages/home/domain/entity/cases_model.dart'; |
12 | import '../lib/pages/home/presentation/controllers/home_controller.dart'; | 13 | import '../lib/pages/home/presentation/controllers/home_controller.dart'; |
13 | 14 | ||
14 | -class MockRepository implements IHomeRepository { | 15 | + |
16 | +class MockRepositorySuccess implements IHomeRepository { | ||
17 | + | ||
15 | @override | 18 | @override |
16 | Future<CasesModel> getCases() async { | 19 | Future<CasesModel> getCases() async { |
17 | - await Future.delayed(Duration(milliseconds: 100)); | ||
18 | - | ||
19 | - if (Random().nextBool()) { | ||
20 | return CasesModel( | 20 | return CasesModel( |
21 | global: Global( | 21 | global: Global( |
22 | totalDeaths: 100, | 22 | totalDeaths: 100, |
@@ -32,7 +32,11 @@ class MockRepository implements IHomeRepository { | @@ -32,7 +32,11 @@ class MockRepository implements IHomeRepository { | ||
32 | message: '', | 32 | message: '', |
33 | ); | 33 | ); |
34 | } | 34 | } |
35 | +} | ||
35 | 36 | ||
37 | +class MockRepositoryFailure implements IHomeRepository { | ||
38 | + @override | ||
39 | + Future<CasesModel> getCases() async { | ||
36 | return Future<CasesModel>.error('error'); | 40 | return Future<CasesModel>.error('error'); |
37 | } | 41 | } |
38 | } | 42 | } |
@@ -41,28 +45,18 @@ void main() { | @@ -41,28 +45,18 @@ void main() { | ||
41 | WidgetsFlutterBinding.ensureInitialized(); | 45 | WidgetsFlutterBinding.ensureInitialized(); |
42 | setUpAll(() => HttpOverrides.global = null); | 46 | setUpAll(() => HttpOverrides.global = null); |
43 | final binding = BindingsBuilder(() { | 47 | final binding = BindingsBuilder(() { |
44 | - Get.lazyPut<IHomeRepository>(() => MockRepository()); | 48 | + Get.lazyPut<IHomeRepository>(() => MockRepositorySuccess()); |
45 | Get.lazyPut<HomeController>( | 49 | Get.lazyPut<HomeController>( |
46 | - () => HomeController(homeRepository: Get.find())); | 50 | + () => HomeController(homeRepository: Get.find()), |
51 | + ); | ||
47 | }); | 52 | }); |
48 | 53 | ||
49 | - test('Test Binding', () { | ||
50 | - expect(Get.isPrepared<HomeController>(), false); | ||
51 | - expect(Get.isPrepared<IHomeRepository>(), false); | ||
52 | - | ||
53 | - /// test you Binding class with BindingsBuilder | ||
54 | - binding.builder(); | ||
55 | - | ||
56 | - expect(Get.isPrepared<HomeController>(), true); | ||
57 | - expect(Get.isPrepared<IHomeRepository>(), true); | ||
58 | - | ||
59 | - Get.reset(); | ||
60 | - }); | ||
61 | test('Test Controller', () async { | 54 | test('Test Controller', () async { |
62 | /// Controller can't be on memory | 55 | /// Controller can't be on memory |
63 | - expect(() => Get.find<HomeController>(), throwsA(m.TypeMatcher<String>())); | 56 | + expect(() => Get.find<HomeController>(tag: 'success'), |
57 | + throwsA(m.TypeMatcher<String>())); | ||
64 | 58 | ||
65 | - /// build Binding | 59 | + /// binding will put the controller on memory |
66 | binding.builder(); | 60 | binding.builder(); |
67 | 61 | ||
68 | /// recover your controller | 62 | /// recover your controller |
@@ -77,24 +71,15 @@ void main() { | @@ -77,24 +71,15 @@ void main() { | ||
77 | /// await time request | 71 | /// await time request |
78 | await Future.delayed(Duration(milliseconds: 100)); | 72 | await Future.delayed(Duration(milliseconds: 100)); |
79 | 73 | ||
80 | - if (controller.status.isError) { | ||
81 | - expect(controller.state, null); | ||
82 | - } | 74 | + /// test if status is success |
75 | + expect(controller.status.isSuccess, true); | ||
76 | + expect(controller.state.global.totalDeaths, 100); | ||
77 | + expect(controller.state.global.totalConfirmed, 200); | ||
83 | 78 | ||
84 | - if (controller.status.isSuccess) { | ||
85 | - expect(controller.state!.global.totalDeaths, 100); | ||
86 | - expect(controller.state!.global.totalConfirmed, 200); | ||
87 | - } | ||
88 | - }); | ||
89 | - | ||
90 | - test('ever', () async { | ||
91 | - final count = ''.obs; | ||
92 | - var result = ''; | ||
93 | - ever<String>(count, (value) { | ||
94 | - result = value; | ||
95 | - }); | ||
96 | - count.value = '1'; | ||
97 | - expect('1', result); | 79 | + /// test if status is error |
80 | + Get.lazyReplace<IHomeRepository>(() => MockRepositoryFailure()); | ||
81 | + expect(controller.status.isError, true); | ||
82 | + expect(controller.state, null); | ||
98 | }); | 83 | }); |
99 | 84 | ||
100 | /// Tests with GetTests | 85 | /// Tests with GetTests |
@@ -151,26 +136,3 @@ void main() { | @@ -151,26 +136,3 @@ void main() { | ||
151 | }, | 136 | }, |
152 | );*/ | 137 | );*/ |
153 | } | 138 | } |
154 | - | ||
155 | -class Controller extends GetxController { | ||
156 | - final count = 0.obs; | ||
157 | - void increment() => count.value++; | ||
158 | - | ||
159 | - @override | ||
160 | - void onInit() { | ||
161 | - print('inittt'); | ||
162 | - super.onInit(); | ||
163 | - } | ||
164 | - | ||
165 | - @override | ||
166 | - void onReady() { | ||
167 | - print('onReady'); | ||
168 | - super.onReady(); | ||
169 | - } | ||
170 | - | ||
171 | - @override | ||
172 | - void onClose() { | ||
173 | - super.onClose(); | ||
174 | - print('onClose'); | ||
175 | - } | ||
176 | -} |
@@ -21,6 +21,6 @@ | @@ -21,6 +21,6 @@ | ||
21 | <key>CFBundleVersion</key> | 21 | <key>CFBundleVersion</key> |
22 | <string>1.0</string> | 22 | <string>1.0</string> |
23 | <key>MinimumOSVersion</key> | 23 | <key>MinimumOSVersion</key> |
24 | - <string>8.0</string> | 24 | + <string>9.0</string> |
25 | </dict> | 25 | </dict> |
26 | </plist> | 26 | </plist> |
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | archiveVersion = 1; | 3 | archiveVersion = 1; |
4 | classes = { | 4 | classes = { |
5 | }; | 5 | }; |
6 | - objectVersion = 46; | 6 | + objectVersion = 50; |
7 | objects = { | 7 | objects = { |
8 | 8 | ||
9 | /* Begin PBXBuildFile section */ | 9 | /* Begin PBXBuildFile section */ |
@@ -127,7 +127,7 @@ | @@ -127,7 +127,7 @@ | ||
127 | 97C146E61CF9000F007C117D /* Project object */ = { | 127 | 97C146E61CF9000F007C117D /* Project object */ = { |
128 | isa = PBXProject; | 128 | isa = PBXProject; |
129 | attributes = { | 129 | attributes = { |
130 | - LastUpgradeCheck = 1020; | 130 | + LastUpgradeCheck = 1300; |
131 | ORGANIZATIONNAME = ""; | 131 | ORGANIZATIONNAME = ""; |
132 | TargetAttributes = { | 132 | TargetAttributes = { |
133 | 97C146ED1CF9000F007C117D = { | 133 | 97C146ED1CF9000F007C117D = { |
@@ -5,14 +5,14 @@ import '../routes/app_pages.dart'; | @@ -5,14 +5,14 @@ import '../routes/app_pages.dart'; | ||
5 | 5 | ||
6 | class EnsureAuthMiddleware extends GetMiddleware { | 6 | class EnsureAuthMiddleware extends GetMiddleware { |
7 | @override | 7 | @override |
8 | - Future<GetNavConfig?> redirectDelegate(GetNavConfig route) async { | 8 | + Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async { |
9 | // you can do whatever you want here | 9 | // you can do whatever you want here |
10 | // but it's preferable to make this method fast | 10 | // but it's preferable to make this method fast |
11 | // await Future.delayed(Duration(milliseconds: 500)); | 11 | // await Future.delayed(Duration(milliseconds: 500)); |
12 | 12 | ||
13 | if (!AuthService.to.isLoggedInValue) { | 13 | if (!AuthService.to.isLoggedInValue) { |
14 | - final newRoute = Routes.LOGIN_THEN(route.location!); | ||
15 | - return GetNavConfig.fromRoute(newRoute); | 14 | + final newRoute = Routes.LOGIN_THEN(route.pageSettings!.name); |
15 | + return RouteDecoder.fromRoute(newRoute); | ||
16 | } | 16 | } |
17 | return await super.redirectDelegate(route); | 17 | return await super.redirectDelegate(route); |
18 | } | 18 | } |
@@ -20,13 +20,13 @@ class EnsureAuthMiddleware extends GetMiddleware { | @@ -20,13 +20,13 @@ class EnsureAuthMiddleware extends GetMiddleware { | ||
20 | 20 | ||
21 | class EnsureNotAuthedMiddleware extends GetMiddleware { | 21 | class EnsureNotAuthedMiddleware extends GetMiddleware { |
22 | @override | 22 | @override |
23 | - Future<GetNavConfig?> redirectDelegate(GetNavConfig route) async { | 23 | + Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async { |
24 | if (AuthService.to.isLoggedInValue) { | 24 | if (AuthService.to.isLoggedInValue) { |
25 | //NEVER navigate to auth screen, when user is already authed | 25 | //NEVER navigate to auth screen, when user is already authed |
26 | return null; | 26 | return null; |
27 | 27 | ||
28 | //OR redirect user to another screen | 28 | //OR redirect user to another screen |
29 | - //return GetNavConfig.fromRoute(Routes.PROFILE); | 29 | + //return RouteDecoder.fromRoute(Routes.PROFILE); |
30 | } | 30 | } |
31 | return await super.redirectDelegate(route); | 31 | return await super.redirectDelegate(route); |
32 | } | 32 | } |
@@ -2,11 +2,13 @@ import 'package:get/get.dart'; | @@ -2,11 +2,13 @@ import 'package:get/get.dart'; | ||
2 | 2 | ||
3 | import '../controllers/dashboard_controller.dart'; | 3 | import '../controllers/dashboard_controller.dart'; |
4 | 4 | ||
5 | -class DashboardBinding extends Bindings { | 5 | +class DashboardBinding extends Binding { |
6 | @override | 6 | @override |
7 | - void dependencies() { | ||
8 | - Get.lazyPut<DashboardController>( | 7 | + List<Bind> dependencies() { |
8 | + return [ | ||
9 | + Bind.lazyPut<DashboardController>( | ||
9 | () => DashboardController(), | 10 | () => DashboardController(), |
10 | - ); | 11 | + ) |
12 | + ]; | ||
11 | } | 13 | } |
12 | } | 14 | } |
@@ -2,11 +2,13 @@ import 'package:get/get.dart'; | @@ -2,11 +2,13 @@ import 'package:get/get.dart'; | ||
2 | 2 | ||
3 | import '../controllers/home_controller.dart'; | 3 | import '../controllers/home_controller.dart'; |
4 | 4 | ||
5 | -class HomeBinding extends Bindings { | 5 | +class HomeBinding extends Binding { |
6 | @override | 6 | @override |
7 | - void dependencies() { | ||
8 | - Get.lazyPut<HomeController>( | 7 | + List<Bind> dependencies() { |
8 | + return [ | ||
9 | + Bind.lazyPut<HomeController>( | ||
9 | () => HomeController(), | 10 | () => HomeController(), |
10 | - ); | 11 | + ) |
12 | + ]; | ||
11 | } | 13 | } |
12 | } | 14 | } |
@@ -5,24 +5,29 @@ import '../../../routes/app_pages.dart'; | @@ -5,24 +5,29 @@ import '../../../routes/app_pages.dart'; | ||
5 | import '../controllers/home_controller.dart'; | 5 | import '../controllers/home_controller.dart'; |
6 | 6 | ||
7 | class HomeView extends GetView<HomeController> { | 7 | class HomeView extends GetView<HomeController> { |
8 | + const HomeView({Key? key}) : super(key: key); | ||
8 | @override | 9 | @override |
9 | Widget build(BuildContext context) { | 10 | Widget build(BuildContext context) { |
10 | return GetRouterOutlet.builder( | 11 | return GetRouterOutlet.builder( |
11 | - builder: (context, delegate, currentRoute) { | 12 | + routerDelegate: Get.nestedKey(Routes.HOME), |
13 | + builder: (context) { | ||
14 | + final delegate = context.navigation; | ||
12 | //This router outlet handles the appbar and the bottom navigation bar | 15 | //This router outlet handles the appbar and the bottom navigation bar |
13 | - final currentLocation = currentRoute?.location; | 16 | + final currentLocation = context.location; |
14 | var currentIndex = 0; | 17 | var currentIndex = 0; |
15 | - if (currentLocation?.startsWith(Routes.PRODUCTS) == true) { | 18 | + if (currentLocation.startsWith(Routes.PRODUCTS) == true) { |
16 | currentIndex = 2; | 19 | currentIndex = 2; |
17 | } | 20 | } |
18 | - if (currentLocation?.startsWith(Routes.PROFILE) == true) { | 21 | + if (currentLocation.startsWith(Routes.PROFILE) == true) { |
19 | currentIndex = 1; | 22 | currentIndex = 1; |
20 | } | 23 | } |
21 | return Scaffold( | 24 | return Scaffold( |
22 | body: GetRouterOutlet( | 25 | body: GetRouterOutlet( |
23 | initialRoute: Routes.DASHBOARD, | 26 | initialRoute: Routes.DASHBOARD, |
24 | - // anchorRoute: Routes.HOME, | ||
25 | - key: Get.nestedKey(Routes.HOME), | 27 | + anchorRoute: Routes.HOME, |
28 | + | ||
29 | + //delegate: Get.nestedKey(Routes.HOME), | ||
30 | + // key: Get.nestedKey(Routes.HOME), | ||
26 | ), | 31 | ), |
27 | bottomNavigationBar: BottomNavigationBar( | 32 | bottomNavigationBar: BottomNavigationBar( |
28 | currentIndex: currentIndex, | 33 | currentIndex: currentIndex, |
@@ -2,11 +2,11 @@ import 'package:get/get.dart'; | @@ -2,11 +2,11 @@ import 'package:get/get.dart'; | ||
2 | 2 | ||
3 | import '../controllers/login_controller.dart'; | 3 | import '../controllers/login_controller.dart'; |
4 | 4 | ||
5 | -class LoginBinding extends Bindings { | 5 | +class LoginBinding extends Binding { |
6 | @override | 6 | @override |
7 | - void dependencies() { | ||
8 | - Get.lazyPut<LoginController>( | ||
9 | - () => LoginController(), | ||
10 | - ); | 7 | + List<Bind> dependencies() { |
8 | + return [ | ||
9 | + Bind.lazyPut(() => LoginController()), | ||
10 | + ]; | ||
11 | } | 11 | } |
12 | } | 12 | } |
@@ -31,9 +31,8 @@ class LoginView extends GetView<LoginController> { | @@ -31,9 +31,8 @@ class LoginView extends GetView<LoginController> { | ||
31 | ), | 31 | ), |
32 | onPressed: () { | 32 | onPressed: () { |
33 | AuthService.to.login(); | 33 | AuthService.to.login(); |
34 | - final thenTo = Get.rootDelegate.currentConfiguration! | ||
35 | - .currentPage!.parameters?['then']; | ||
36 | - Get.rootDelegate.offNamed(thenTo ?? Routes.HOME); | 34 | + final thenTo = context.params['then']; |
35 | + Get.offNamed(thenTo ?? Routes.HOME); | ||
37 | }, | 36 | }, |
38 | ), | 37 | ), |
39 | ], | 38 | ], |
@@ -2,13 +2,15 @@ import 'package:get/get.dart'; | @@ -2,13 +2,15 @@ import 'package:get/get.dart'; | ||
2 | 2 | ||
3 | import '../controllers/product_details_controller.dart'; | 3 | import '../controllers/product_details_controller.dart'; |
4 | 4 | ||
5 | -class ProductDetailsBinding extends Bindings { | 5 | +class ProductDetailsBinding extends Binding { |
6 | @override | 6 | @override |
7 | - void dependencies() { | ||
8 | - Get.create<ProductDetailsController>( | 7 | + List<Bind> dependencies() { |
8 | + return [ | ||
9 | + Bind.create<ProductDetailsController>( | ||
9 | () => ProductDetailsController( | 10 | () => ProductDetailsController( |
10 | Get.parameters['productId'] ?? '', | 11 | Get.parameters['productId'] ?? '', |
11 | ), | 12 | ), |
12 | - ); | 13 | + ) |
14 | + ]; | ||
13 | } | 15 | } |
14 | } | 16 | } |
@@ -13,6 +13,7 @@ class ProductDetailsController extends GetxController { | @@ -13,6 +13,7 @@ class ProductDetailsController extends GetxController { | ||
13 | @override | 13 | @override |
14 | void onClose() { | 14 | void onClose() { |
15 | Get.log('ProductDetailsController close with id: $productId'); | 15 | Get.log('ProductDetailsController close with id: $productId'); |
16 | + | ||
16 | super.onClose(); | 17 | super.onClose(); |
17 | } | 18 | } |
18 | } | 19 | } |
@@ -5,11 +5,12 @@ import '../../../routes/app_pages.dart'; | @@ -5,11 +5,12 @@ import '../../../routes/app_pages.dart'; | ||
5 | import '../controllers/products_controller.dart'; | 5 | import '../controllers/products_controller.dart'; |
6 | 6 | ||
7 | class ProductsView extends GetView<ProductsController> { | 7 | class ProductsView extends GetView<ProductsController> { |
8 | + const ProductsView({Key? key}) : super(key: key); | ||
8 | @override | 9 | @override |
9 | Widget build(BuildContext context) { | 10 | Widget build(BuildContext context) { |
10 | return Scaffold( | 11 | return Scaffold( |
11 | floatingActionButton: FloatingActionButton.extended( | 12 | floatingActionButton: FloatingActionButton.extended( |
12 | - onPressed: controller.loadDemoProductsFromSomeWhere, | 13 | + onPressed: () => controller.loadDemoProductsFromSomeWhere(), |
13 | label: Text('Add'), | 14 | label: Text('Add'), |
14 | ), | 15 | ), |
15 | body: Column( | 16 | body: Column( |
@@ -31,8 +32,7 @@ class ProductsView extends GetView<ProductsController> { | @@ -31,8 +32,7 @@ class ProductsView extends GetView<ProductsController> { | ||
31 | final item = controller.products[index]; | 32 | final item = controller.products[index]; |
32 | return ListTile( | 33 | return ListTile( |
33 | onTap: () { | 34 | onTap: () { |
34 | - Get.rootDelegate | ||
35 | - .toNamed(Routes.PRODUCT_DETAILS(item.id)); | 35 | + Get.toNamed(Routes.PRODUCT_DETAILS(item.id)); |
36 | }, | 36 | }, |
37 | title: Text(item.name), | 37 | title: Text(item.name), |
38 | subtitle: Text(item.id), | 38 | subtitle: Text(item.id), |
@@ -2,11 +2,13 @@ import 'package:get/get.dart'; | @@ -2,11 +2,13 @@ import 'package:get/get.dart'; | ||
2 | 2 | ||
3 | import '../controllers/profile_controller.dart'; | 3 | import '../controllers/profile_controller.dart'; |
4 | 4 | ||
5 | -class ProfileBinding extends Bindings { | 5 | +class ProfileBinding extends Binding { |
6 | @override | 6 | @override |
7 | - void dependencies() { | ||
8 | - Get.lazyPut<ProfileController>( | 7 | + List<Bind> dependencies() { |
8 | + return [ | ||
9 | + Bind.lazyPut<ProfileController>( | ||
9 | () => ProfileController(), | 10 | () => ProfileController(), |
10 | - ); | 11 | + ) |
12 | + ]; | ||
11 | } | 13 | } |
12 | } | 14 | } |
@@ -39,7 +39,8 @@ class ProfileView extends GetView<ProfileController> { | @@ -39,7 +39,8 @@ class ProfileView extends GetView<ProfileController> { | ||
39 | Get.defaultDialog( | 39 | Get.defaultDialog( |
40 | title: 'Test Dialog In Home Outlet !!', | 40 | title: 'Test Dialog In Home Outlet !!', |
41 | barrierDismissible: true, | 41 | barrierDismissible: true, |
42 | - navigatorKey: Get.nestedKey(Routes.HOME), | 42 | + id: Routes.HOME, |
43 | + // navigatorKey: Get.nestedKey(Routes.HOME), | ||
43 | ); | 44 | ); |
44 | }, | 45 | }, |
45 | ) | 46 | ) |
@@ -2,11 +2,13 @@ import 'package:get/get.dart'; | @@ -2,11 +2,13 @@ import 'package:get/get.dart'; | ||
2 | 2 | ||
3 | import '../controllers/root_controller.dart'; | 3 | import '../controllers/root_controller.dart'; |
4 | 4 | ||
5 | -class RootBinding extends Bindings { | 5 | +class RootBinding extends Binding { |
6 | @override | 6 | @override |
7 | - void dependencies() { | ||
8 | - Get.lazyPut<RootController>( | 7 | + List<Bind> dependencies() { |
8 | + return [ | ||
9 | + Bind.lazyPut<RootController>( | ||
9 | () => RootController(), | 10 | () => RootController(), |
10 | - ); | 11 | + ) |
12 | + ]; | ||
11 | } | 13 | } |
12 | } | 14 | } |
@@ -21,7 +21,7 @@ class DrawerWidget extends StatelessWidget { | @@ -21,7 +21,7 @@ class DrawerWidget extends StatelessWidget { | ||
21 | ListTile( | 21 | ListTile( |
22 | title: Text('Home'), | 22 | title: Text('Home'), |
23 | onTap: () { | 23 | onTap: () { |
24 | - Get.rootDelegate.toNamed(Routes.HOME); | 24 | + Get.toNamed(Routes.HOME); |
25 | //to close the drawer | 25 | //to close the drawer |
26 | 26 | ||
27 | Navigator.of(context).pop(); | 27 | Navigator.of(context).pop(); |
@@ -30,7 +30,7 @@ class DrawerWidget extends StatelessWidget { | @@ -30,7 +30,7 @@ class DrawerWidget extends StatelessWidget { | ||
30 | ListTile( | 30 | ListTile( |
31 | title: Text('Settings'), | 31 | title: Text('Settings'), |
32 | onTap: () { | 32 | onTap: () { |
33 | - Get.rootDelegate.toNamed(Routes.SETTINGS); | 33 | + Get.toNamed(Routes.SETTINGS); |
34 | //to close the drawer | 34 | //to close the drawer |
35 | 35 | ||
36 | Navigator.of(context).pop(); | 36 | Navigator.of(context).pop(); |
@@ -46,7 +46,7 @@ class DrawerWidget extends StatelessWidget { | @@ -46,7 +46,7 @@ class DrawerWidget extends StatelessWidget { | ||
46 | ), | 46 | ), |
47 | onTap: () { | 47 | onTap: () { |
48 | AuthService.to.logout(); | 48 | AuthService.to.logout(); |
49 | - Get.rootDelegate.toNamed(Routes.LOGIN); | 49 | + Get.toNamed(Routes.LOGIN); |
50 | //to close the drawer | 50 | //to close the drawer |
51 | 51 | ||
52 | Navigator.of(context).pop(); | 52 | Navigator.of(context).pop(); |
@@ -61,7 +61,7 @@ class DrawerWidget extends StatelessWidget { | @@ -61,7 +61,7 @@ class DrawerWidget extends StatelessWidget { | ||
61 | ), | 61 | ), |
62 | ), | 62 | ), |
63 | onTap: () { | 63 | onTap: () { |
64 | - Get.rootDelegate.toNamed(Routes.LOGIN); | 64 | + Get.toNamed(Routes.LOGIN); |
65 | //to close the drawer | 65 | //to close the drawer |
66 | 66 | ||
67 | Navigator.of(context).pop(); | 67 | Navigator.of(context).pop(); |
@@ -8,21 +8,28 @@ import 'drawer.dart'; | @@ -8,21 +8,28 @@ import 'drawer.dart'; | ||
8 | class RootView extends GetView<RootController> { | 8 | class RootView extends GetView<RootController> { |
9 | @override | 9 | @override |
10 | Widget build(BuildContext context) { | 10 | Widget build(BuildContext context) { |
11 | - return GetRouterOutlet.builder( | ||
12 | - builder: (context, delegate, current) { | ||
13 | - final title = current?.location; | 11 | + return RouterOutlet.builder( |
12 | + delegate: Get.nestedKey(null), | ||
13 | + builder: (context) { | ||
14 | + final title = context.location; | ||
14 | return Scaffold( | 15 | return Scaffold( |
15 | drawer: DrawerWidget(), | 16 | drawer: DrawerWidget(), |
16 | appBar: AppBar( | 17 | appBar: AppBar( |
17 | - title: Text(title ?? ''), | 18 | + title: Text(title), |
18 | centerTitle: true, | 19 | centerTitle: true, |
19 | ), | 20 | ), |
21 | + //body: HomeView(), | ||
22 | + | ||
20 | body: GetRouterOutlet( | 23 | body: GetRouterOutlet( |
21 | initialRoute: Routes.HOME, | 24 | initialRoute: Routes.HOME, |
22 | - // anchorRoute: '/', | ||
23 | - // filterPages: (afterAnchor) { | ||
24 | - // return afterAnchor.take(1); | ||
25 | - // }, | 25 | + delegate: Get.nestedKey(null), |
26 | + anchorRoute: '/', | ||
27 | + filterPages: (afterAnchor) { | ||
28 | + // print(afterAnchor); | ||
29 | + // print('dddddddddddddddddd'); | ||
30 | + // print(afterAnchor.take(1)); | ||
31 | + return afterAnchor.take(1); | ||
32 | + }, | ||
26 | ), | 33 | ), |
27 | ); | 34 | ); |
28 | }, | 35 | }, |
@@ -2,11 +2,13 @@ import 'package:get/get.dart'; | @@ -2,11 +2,13 @@ import 'package:get/get.dart'; | ||
2 | 2 | ||
3 | import '../controllers/settings_controller.dart'; | 3 | import '../controllers/settings_controller.dart'; |
4 | 4 | ||
5 | -class SettingsBinding extends Bindings { | 5 | +class SettingsBinding extends Binding { |
6 | @override | 6 | @override |
7 | - void dependencies() { | ||
8 | - Get.lazyPut<SettingsController>( | 7 | + List<Bind> dependencies() { |
8 | + return [ | ||
9 | + Bind.lazyPut<SettingsController>( | ||
9 | () => SettingsController(), | 10 | () => SettingsController(), |
10 | - ); | 11 | + ) |
12 | + ]; | ||
11 | } | 13 | } |
12 | } | 14 | } |
1 | +import 'dart:async'; | ||
2 | + | ||
3 | +import 'package:async/async.dart'; | ||
4 | +import 'package:get/get.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 | +} |
@@ -29,7 +29,7 @@ class AppPages { | @@ -29,7 +29,7 @@ class AppPages { | ||
29 | GetPage( | 29 | GetPage( |
30 | name: '/', | 30 | name: '/', |
31 | page: () => RootView(), | 31 | page: () => RootView(), |
32 | - binding: RootBinding(), | 32 | + bindings: [RootBinding()], |
33 | participatesInRootNavigator: true, | 33 | participatesInRootNavigator: true, |
34 | preventDuplicates: true, | 34 | preventDuplicates: true, |
35 | children: [ | 35 | children: [ |
@@ -40,12 +40,12 @@ class AppPages { | @@ -40,12 +40,12 @@ class AppPages { | ||
40 | ], | 40 | ], |
41 | name: _Paths.LOGIN, | 41 | name: _Paths.LOGIN, |
42 | page: () => LoginView(), | 42 | page: () => LoginView(), |
43 | - binding: LoginBinding(), | 43 | + bindings: [LoginBinding()], |
44 | ), | 44 | ), |
45 | GetPage( | 45 | GetPage( |
46 | preventDuplicates: true, | 46 | preventDuplicates: true, |
47 | name: _Paths.HOME, | 47 | name: _Paths.HOME, |
48 | - page: () => HomeView(), | 48 | + page: () => const HomeView(), |
49 | bindings: [ | 49 | bindings: [ |
50 | HomeBinding(), | 50 | HomeBinding(), |
51 | ], | 51 | ], |
@@ -54,7 +54,9 @@ class AppPages { | @@ -54,7 +54,9 @@ class AppPages { | ||
54 | GetPage( | 54 | GetPage( |
55 | name: _Paths.DASHBOARD, | 55 | name: _Paths.DASHBOARD, |
56 | page: () => DashboardView(), | 56 | page: () => DashboardView(), |
57 | - binding: DashboardBinding(), | 57 | + bindings: [ |
58 | + DashboardBinding(), | ||
59 | + ], | ||
58 | ), | 60 | ), |
59 | GetPage( | 61 | GetPage( |
60 | middlewares: [ | 62 | middlewares: [ |
@@ -65,19 +67,20 @@ class AppPages { | @@ -65,19 +67,20 @@ class AppPages { | ||
65 | page: () => ProfileView(), | 67 | page: () => ProfileView(), |
66 | title: 'Profile', | 68 | title: 'Profile', |
67 | transition: Transition.size, | 69 | transition: Transition.size, |
68 | - binding: ProfileBinding(), | 70 | + bindings: [ProfileBinding()], |
69 | ), | 71 | ), |
70 | GetPage( | 72 | GetPage( |
71 | name: _Paths.PRODUCTS, | 73 | name: _Paths.PRODUCTS, |
72 | - page: () => ProductsView(), | 74 | + page: () => const ProductsView(), |
73 | title: 'Products', | 75 | title: 'Products', |
74 | transition: Transition.zoom, | 76 | transition: Transition.zoom, |
75 | - binding: ProductsBinding(), | 77 | + participatesInRootNavigator: false, |
78 | + bindings: [ProductsBinding()], | ||
76 | children: [ | 79 | children: [ |
77 | GetPage( | 80 | GetPage( |
78 | name: _Paths.PRODUCT_DETAILS, | 81 | name: _Paths.PRODUCT_DETAILS, |
79 | page: () => ProductDetailsView(), | 82 | page: () => ProductDetailsView(), |
80 | - binding: ProductDetailsBinding(), | 83 | + bindings: [ProductDetailsBinding()], |
81 | middlewares: [ | 84 | middlewares: [ |
82 | //only enter this route when authed | 85 | //only enter this route when authed |
83 | EnsureAuthMiddleware(), | 86 | EnsureAuthMiddleware(), |
@@ -90,7 +93,9 @@ class AppPages { | @@ -90,7 +93,9 @@ class AppPages { | ||
90 | GetPage( | 93 | GetPage( |
91 | name: _Paths.SETTINGS, | 94 | name: _Paths.SETTINGS, |
92 | page: () => SettingsView(), | 95 | page: () => SettingsView(), |
93 | - binding: SettingsBinding(), | 96 | + bindings: [ |
97 | + SettingsBinding(), | ||
98 | + ], | ||
94 | ), | 99 | ), |
95 | ], | 100 | ], |
96 | ), | 101 | ), |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | import 'package:get/get.dart'; | 2 | import 'package:get/get.dart'; |
3 | 3 | ||
4 | +import 'app/modules/splash/controllers/splash_service.dart'; | ||
4 | import 'app/routes/app_pages.dart'; | 5 | import 'app/routes/app_pages.dart'; |
5 | import 'services/auth_service.dart'; | 6 | import 'services/auth_service.dart'; |
6 | 7 | ||
7 | void main() { | 8 | void main() { |
8 | runApp( | 9 | runApp( |
9 | - GetMaterialApp.router( | 10 | + GetMaterialApp( |
10 | title: "Application", | 11 | title: "Application", |
11 | initialBinding: BindingsBuilder( | 12 | initialBinding: BindingsBuilder( |
12 | () { | 13 | () { |
14 | + Get.put(SplashService()); | ||
13 | Get.put(AuthService()); | 15 | Get.put(AuthService()); |
14 | }, | 16 | }, |
15 | ), | 17 | ), |
16 | getPages: AppPages.routes, | 18 | getPages: AppPages.routes, |
19 | + initialRoute: AppPages.INITIAL, | ||
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 | // ), |
@@ -7,12 +7,12 @@ environment: | @@ -7,12 +7,12 @@ environment: | ||
7 | 7 | ||
8 | dependencies: | 8 | dependencies: |
9 | cupertino_icons: ^1.0.2 | 9 | cupertino_icons: ^1.0.2 |
10 | - effective_dart: 1.3.1 | ||
11 | # get: ^4.1.4 | 10 | # get: ^4.1.4 |
12 | get: | 11 | get: |
13 | path: ../ | 12 | path: ../ |
14 | flutter: | 13 | flutter: |
15 | sdk: flutter | 14 | sdk: flutter |
15 | + flutter_lints: ^1.0.4 | ||
16 | 16 | ||
17 | dev_dependencies: | 17 | dev_dependencies: |
18 | flutter_test: | 18 | flutter_test: |
@@ -12,7 +12,7 @@ export 'http/src/multipart/multipart_file.dart'; | @@ -12,7 +12,7 @@ export 'http/src/multipart/multipart_file.dart'; | ||
12 | export 'http/src/response/response.dart'; | 12 | export 'http/src/response/response.dart'; |
13 | export 'sockets/sockets.dart'; | 13 | export 'sockets/sockets.dart'; |
14 | 14 | ||
15 | -abstract class GetConnectInterface with GetLifeCycleBase { | 15 | +abstract class GetConnectInterface with GetLifeCycleMixin { |
16 | List<GetSocket>? sockets; | 16 | List<GetSocket>? sockets; |
17 | GetHttpClient get httpClient; | 17 | GetHttpClient get httpClient; |
18 | 18 | ||
@@ -100,9 +100,7 @@ class GetConnect extends GetConnectInterface { | @@ -100,9 +100,7 @@ class GetConnect extends GetConnectInterface { | ||
100 | this.maxAuthRetries = 1, | 100 | this.maxAuthRetries = 1, |
101 | this.allowAutoSignedCert = false, | 101 | this.allowAutoSignedCert = false, |
102 | this.withCredentials = false, | 102 | this.withCredentials = false, |
103 | - }) { | ||
104 | - $configureLifeCycle(); | ||
105 | - } | 103 | + }); |
106 | 104 | ||
107 | bool allowAutoSignedCert; | 105 | bool allowAutoSignedCert; |
108 | String userAgent; | 106 | String userAgent; |
@@ -135,8 +133,7 @@ class GetConnect extends GetConnectInterface { | @@ -135,8 +133,7 @@ class GetConnect extends GetConnectInterface { | ||
135 | baseUrl: baseUrl, | 133 | baseUrl: baseUrl, |
136 | trustedCertificates: trustedCertificates, | 134 | trustedCertificates: trustedCertificates, |
137 | withCredentials: withCredentials, | 135 | withCredentials: withCredentials, |
138 | - findProxy: findProxy | ||
139 | - ); | 136 | + findProxy: findProxy); |
140 | 137 | ||
141 | @override | 138 | @override |
142 | Future<Response<T>> get<T>( | 139 | Future<Response<T>> get<T>( |
@@ -28,6 +28,7 @@ class GetHttpClient { | @@ -28,6 +28,7 @@ class GetHttpClient { | ||
28 | int maxAuthRetries; | 28 | int maxAuthRetries; |
29 | 29 | ||
30 | bool sendUserAgent; | 30 | bool sendUserAgent; |
31 | + bool sendContentLength; | ||
31 | 32 | ||
32 | Decoder? defaultDecoder; | 33 | Decoder? defaultDecoder; |
33 | 34 | ||
@@ -47,6 +48,7 @@ class GetHttpClient { | @@ -47,6 +48,7 @@ class GetHttpClient { | ||
47 | this.followRedirects = true, | 48 | this.followRedirects = true, |
48 | this.maxRedirects = 5, | 49 | this.maxRedirects = 5, |
49 | this.sendUserAgent = false, | 50 | this.sendUserAgent = false, |
51 | + this.sendContentLength = true, | ||
50 | this.maxAuthRetries = 1, | 52 | this.maxAuthRetries = 1, |
51 | bool allowAutoSignedCert = false, | 53 | bool allowAutoSignedCert = false, |
52 | this.baseUrl, | 54 | this.baseUrl, |
@@ -111,7 +113,7 @@ class GetHttpClient { | @@ -111,7 +113,7 @@ class GetHttpClient { | ||
111 | 113 | ||
112 | if (body is FormData) { | 114 | if (body is FormData) { |
113 | bodyBytes = await body.toBytes(); | 115 | bodyBytes = await body.toBytes(); |
114 | - headers['content-length'] = bodyBytes.length.toString(); | 116 | + _setContentLenght(headers, bodyBytes.length); |
115 | headers['content-type'] = | 117 | headers['content-type'] = |
116 | 'multipart/form-data; boundary=${body.boundary}'; | 118 | 'multipart/form-data; boundary=${body.boundary}'; |
117 | } else if (contentType != null && | 119 | } else if (contentType != null && |
@@ -124,21 +126,21 @@ class GetHttpClient { | @@ -124,21 +126,21 @@ class GetHttpClient { | ||
124 | }); | 126 | }); |
125 | var formData = parts.join('&'); | 127 | var formData = parts.join('&'); |
126 | bodyBytes = utf8.encode(formData); | 128 | bodyBytes = utf8.encode(formData); |
127 | - headers['content-length'] = bodyBytes.length.toString(); | 129 | + _setContentLenght(headers, bodyBytes.length); |
128 | headers['content-type'] = contentType; | 130 | headers['content-type'] = contentType; |
129 | } else if (body is Map || body is List) { | 131 | } else if (body is Map || body is List) { |
130 | var jsonString = json.encode(body); | 132 | var jsonString = json.encode(body); |
131 | - | ||
132 | bodyBytes = utf8.encode(jsonString); | 133 | bodyBytes = utf8.encode(jsonString); |
133 | - headers['content-length'] = bodyBytes.length.toString(); | 134 | + _setContentLenght(headers, bodyBytes.length); |
134 | headers['content-type'] = contentType ?? defaultContentType; | 135 | headers['content-type'] = contentType ?? defaultContentType; |
135 | } else if (body is String) { | 136 | } else if (body is String) { |
136 | bodyBytes = utf8.encode(body); | 137 | bodyBytes = utf8.encode(body); |
137 | - headers['content-length'] = bodyBytes.length.toString(); | 138 | + _setContentLenght(headers, bodyBytes.length); |
139 | + | ||
138 | headers['content-type'] = contentType ?? defaultContentType; | 140 | headers['content-type'] = contentType ?? defaultContentType; |
139 | } else if (body == null) { | 141 | } else if (body == null) { |
142 | + _setContentLenght(headers, 0); | ||
140 | headers['content-type'] = contentType ?? defaultContentType; | 143 | headers['content-type'] = contentType ?? defaultContentType; |
141 | - headers['content-length'] = '0'; | ||
142 | } else { | 144 | } else { |
143 | if (!errorSafety) { | 145 | if (!errorSafety) { |
144 | throw UnexpectedFormat('body cannot be ${body.runtimeType}'); | 146 | throw UnexpectedFormat('body cannot be ${body.runtimeType}'); |
@@ -162,6 +164,12 @@ class GetHttpClient { | @@ -162,6 +164,12 @@ class GetHttpClient { | ||
162 | ); | 164 | ); |
163 | } | 165 | } |
164 | 166 | ||
167 | + void _setContentLenght(Map<String, String> headers, int contentLength) { | ||
168 | + if (sendContentLength) { | ||
169 | + headers['content-length'] = '$contentLength'; | ||
170 | + } | ||
171 | + } | ||
172 | + | ||
165 | Stream<List<int>> _trackProgress( | 173 | Stream<List<int>> _trackProgress( |
166 | List<int> bodyBytes, | 174 | List<int> bodyBytes, |
167 | Progress? uploadProgress, | 175 | Progress? uploadProgress, |
@@ -14,6 +14,7 @@ class HttpRequestImpl implements HttpRequestBase { | @@ -14,6 +14,7 @@ class HttpRequestImpl implements HttpRequestBase { | ||
14 | bool allowAutoSignedCert = true, | 14 | bool allowAutoSignedCert = true, |
15 | List<TrustedCertificate>? trustedCertificates, | 15 | List<TrustedCertificate>? trustedCertificates, |
16 | this.withCredentials = false, | 16 | this.withCredentials = false, |
17 | + String Function(Uri url)? findProxy, | ||
17 | }); | 18 | }); |
18 | 19 | ||
19 | /// The currently active XHRs. | 20 | /// The currently active XHRs. |
@@ -110,11 +110,12 @@ class BaseWebSocket { | @@ -110,11 +110,12 @@ class BaseWebSocket { | ||
110 | return true; | 110 | return true; |
111 | }; | 111 | }; |
112 | 112 | ||
113 | - var request = await client.getUrl(Uri.parse(url)); | ||
114 | - request.headers.add('Connection', 'Upgrade'); | ||
115 | - request.headers.add('Upgrade', 'websocket'); | ||
116 | - request.headers.add('Sec-WebSocket-Version', '13'); | ||
117 | - request.headers.add('Sec-WebSocket-Key', key.toLowerCase()); | 113 | + var request = await client.getUrl(Uri.parse(url)) |
114 | + ..headers.add('Connection', 'Upgrade') | ||
115 | + ..headers.add('Upgrade', 'websocket') | ||
116 | + ..headers.add('Cache-Control', 'no-cache') | ||
117 | + ..headers.add('Sec-WebSocket-Version', '13') | ||
118 | + ..headers.add('Sec-WebSocket-Key', key.toLowerCase()); | ||
118 | 119 | ||
119 | var response = await request.close(); | 120 | var response = await request.close(); |
120 | // ignore: close_sinks | 121 | // ignore: close_sinks |
1 | typedef ValueUpdater<T> = T Function(); | 1 | typedef ValueUpdater<T> = T Function(); |
2 | +/// This allows a value of type T or T? | ||
3 | +/// to be treated as a value of type T?. | ||
4 | +/// | ||
5 | +/// We use this so that APIs that have become | ||
6 | +/// non-nullable can still be used with `!` and `?` | ||
7 | +/// to support older versions of the API as well. | ||
8 | +T? ambiguate<T>(T? value) => value; |
1 | +// ignore: one_member_abstracts | ||
1 | import 'get_instance.dart'; | 2 | import 'get_instance.dart'; |
2 | 3 | ||
4 | +// ignore: one_member_abstracts | ||
5 | +abstract class BindingsInterface<T> { | ||
6 | + T dependencies(); | ||
7 | +} | ||
8 | + | ||
3 | /// [Bindings] should be extended or implemented. | 9 | /// [Bindings] should be extended or implemented. |
4 | /// When using `GetMaterialApp`, all `GetPage`s and navigation | 10 | /// When using `GetMaterialApp`, all `GetPage`s and navigation |
5 | /// methods (like Get.to()) have a `binding` property that takes an | 11 | /// methods (like Get.to()) have a `binding` property that takes an |
6 | /// instance of Bindings to manage the | 12 | /// instance of Bindings to manage the |
7 | /// dependencies() (via Get.put()) for the Route you are opening. | 13 | /// dependencies() (via Get.put()) for the Route you are opening. |
8 | // ignore: one_member_abstracts | 14 | // ignore: one_member_abstracts |
9 | -abstract class Bindings { | 15 | +@Deprecated('Use Binding instead') |
16 | +abstract class Bindings extends BindingsInterface<void> { | ||
17 | + @override | ||
10 | void dependencies(); | 18 | void dependencies(); |
11 | } | 19 | } |
12 | 20 | ||
@@ -58,8 +66,4 @@ class BindingsBuilder<T> extends Bindings { | @@ -58,8 +66,4 @@ class BindingsBuilder<T> extends Bindings { | ||
58 | } | 66 | } |
59 | } | 67 | } |
60 | 68 | ||
61 | -// abstract class INavigation {} | ||
62 | -// typedef Snack = Function(); | ||
63 | -// typedef Modal = Function(); | ||
64 | -// typedef Route = Function(); | ||
65 | typedef BindingBuilderCallback = void Function(); | 69 | typedef BindingBuilderCallback = void Function(); |
@@ -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. |
@@ -205,7 +200,8 @@ class GetInstance { | @@ -205,7 +200,8 @@ class GetInstance { | ||
205 | if (_singl[key]!.isSingleton!) { | 200 | if (_singl[key]!.isSingleton!) { |
206 | _singl[key]!.isInit = true; | 201 | _singl[key]!.isInit = true; |
207 | if (Get.smartManagement != SmartManagement.onlyBuilder) { | 202 | if (Get.smartManagement != SmartManagement.onlyBuilder) { |
208 | - RouterReportManager.reportDependencyLinkedToRoute(_getKey(S, name)); | 203 | + RouterReportManager.instance |
204 | + .reportDependencyLinkedToRoute(_getKey(S, name)); | ||
209 | } | 205 | } |
210 | } | 206 | } |
211 | } | 207 | } |
@@ -249,7 +245,7 @@ class GetInstance { | @@ -249,7 +245,7 @@ class GetInstance { | ||
249 | S _startController<S>({String? tag}) { | 245 | S _startController<S>({String? tag}) { |
250 | final key = _getKey(S, tag); | 246 | final key = _getKey(S, tag); |
251 | final i = _singl[key]!.getDependency() as S; | 247 | final i = _singl[key]!.getDependency() as S; |
252 | - if (i is GetLifeCycleBase) { | 248 | + if (i is GetLifeCycleMixin) { |
253 | i.onStart(); | 249 | i.onStart(); |
254 | if (tag == null) { | 250 | if (tag == null) { |
255 | Get.log('Instance "$S" has been initialized'); | 251 | Get.log('Instance "$S" has been initialized'); |
@@ -257,7 +253,7 @@ class GetInstance { | @@ -257,7 +253,7 @@ class GetInstance { | ||
257 | Get.log('Instance "$S" with tag "$tag" has been initialized'); | 253 | Get.log('Instance "$S" with tag "$tag" has been initialized'); |
258 | } | 254 | } |
259 | if (!_singl[key]!.isSingleton!) { | 255 | if (!_singl[key]!.isSingleton!) { |
260 | - RouterReportManager.appendRouteByCreate(i); | 256 | + RouterReportManager.instance.appendRouteByCreate(i); |
261 | } | 257 | } |
262 | } | 258 | } |
263 | return i; | 259 | return i; |
@@ -323,7 +319,7 @@ class GetInstance { | @@ -323,7 +319,7 @@ class GetInstance { | ||
323 | {@deprecated bool clearFactory = true, bool clearRouteBindings = true}) { | 319 | {@deprecated bool clearFactory = true, bool clearRouteBindings = true}) { |
324 | // if (clearFactory) _factory.clear(); | 320 | // if (clearFactory) _factory.clear(); |
325 | // deleteAll(force: true); | 321 | // deleteAll(force: true); |
326 | - if (clearRouteBindings) RouterReportManager.clearRouteKeys(); | 322 | + if (clearRouteBindings) RouterReportManager.instance.clearRouteKeys(); |
327 | _singl.clear(); | 323 | _singl.clear(); |
328 | 324 | ||
329 | return true; | 325 | return true; |
@@ -378,7 +374,7 @@ class GetInstance { | @@ -378,7 +374,7 @@ class GetInstance { | ||
378 | return false; | 374 | return false; |
379 | } | 375 | } |
380 | 376 | ||
381 | - if (i is GetLifeCycleBase) { | 377 | + if (i is GetLifeCycleMixin) { |
382 | i.onDelete(); | 378 | i.onDelete(); |
383 | Get.log('"$newKey" onDelete() called'); | 379 | Get.log('"$newKey" onDelete() called'); |
384 | } | 380 | } |
@@ -451,7 +447,7 @@ class GetInstance { | @@ -451,7 +447,7 @@ class GetInstance { | ||
451 | return; | 447 | return; |
452 | } | 448 | } |
453 | 449 | ||
454 | - if (i is GetLifeCycleBase) { | 450 | + if (i is GetLifeCycleMixin) { |
455 | i.onDelete(); | 451 | i.onDelete(); |
456 | Get.log('"$newKey" onDelete() called'); | 452 | Get.log('"$newKey" onDelete() called'); |
457 | } | 453 | } |
@@ -518,14 +514,14 @@ class _InstanceBuilderFactory<S> { | @@ -518,14 +514,14 @@ class _InstanceBuilderFactory<S> { | ||
518 | 514 | ||
519 | String? tag; | 515 | String? tag; |
520 | 516 | ||
521 | - _InstanceBuilderFactory( | ||
522 | - this.isSingleton, | ||
523 | - this.builderFunc, | ||
524 | - this.permanent, | ||
525 | - this.isInit, | ||
526 | - this.fenix, | ||
527 | - this.tag, { | ||
528 | - 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, | ||
529 | }); | 525 | }); |
530 | 526 | ||
531 | void _showInitLog() { | 527 | void _showInitLog() { |
1 | -import '../../get_core/get_core.dart'; | 1 | +import 'package:flutter/foundation.dart'; |
2 | +import 'package:flutter/scheduler.dart'; | ||
2 | 3 | ||
3 | -/// Special callable class to keep the contract of a regular method, and avoid | ||
4 | -/// overrides if you extend the class that uses it, as Dart has no final | ||
5 | -/// methods. | ||
6 | -/// Used in `DisposableInterface` to avoid the danger of overriding onStart. | ||
7 | -class InternalFinalCallback<T> { | ||
8 | - ValueUpdater<T>? _callback; | ||
9 | - | ||
10 | - InternalFinalCallback({ValueUpdater<T>? callback}) : _callback = callback; | ||
11 | - | ||
12 | - T call() => _callback!.call(); | ||
13 | -} | 4 | +import '../../get.dart'; |
14 | 5 | ||
15 | /// The [GetLifeCycle] | 6 | /// The [GetLifeCycle] |
16 | /// | 7 | /// |
@@ -21,26 +12,15 @@ class InternalFinalCallback<T> { | @@ -21,26 +12,15 @@ class InternalFinalCallback<T> { | ||
21 | /// } | 12 | /// } |
22 | /// } | 13 | /// } |
23 | /// ``` | 14 | /// ``` |
24 | -mixin GetLifeCycleBase { | ||
25 | - /// Called at the exact moment the widget is allocated in memory. | ||
26 | - /// It uses an internal "callable" type, to avoid any @overrides in subclases. | ||
27 | - /// This method should be internal and is required to define the | ||
28 | - /// lifetime cycle of the subclass. | ||
29 | - final onStart = InternalFinalCallback<void>(); | ||
30 | - | ||
31 | - // /// The `configureLifeCycle` works as a constructor for the [GetLifeCycle] | ||
32 | - // /// | ||
33 | - // /// This method must be invoked in the constructor of the implementation | ||
34 | - // void configureLifeCycle() { | ||
35 | - // if (_initialized) return; | ||
36 | - // } | ||
37 | - | ||
38 | - /// Internal callback that starts the cycle of this controller. | ||
39 | - final onDelete = InternalFinalCallback<void>(); | ||
40 | - | 15 | +mixin GetLifeCycleMixin { |
41 | /// Called immediately after the widget is allocated in memory. | 16 | /// Called immediately after the widget is allocated in memory. |
42 | /// You might use this to initialize something for the controller. | 17 | /// You might use this to initialize something for the controller. |
43 | - void onInit() {} | 18 | + @protected |
19 | + @mustCallSuper | ||
20 | + void onInit() { | ||
21 | + ambiguate(SchedulerBinding.instance) | ||
22 | + ?.addPostFrameCallback((_) => onReady()); | ||
23 | + } | ||
44 | 24 | ||
45 | /// Called 1 frame after onInit(). It is the perfect place to enter | 25 | /// Called 1 frame after onInit(). It is the perfect place to enter |
46 | /// navigation events, like snackbar, dialogs, or a new route, or | 26 | /// navigation events, like snackbar, dialogs, or a new route, or |
@@ -60,8 +40,15 @@ mixin GetLifeCycleBase { | @@ -60,8 +40,15 @@ mixin GetLifeCycleBase { | ||
60 | /// Checks whether the controller has already been initialized. | 40 | /// Checks whether the controller has already been initialized. |
61 | bool get initialized => _initialized; | 41 | bool get initialized => _initialized; |
62 | 42 | ||
63 | - // Internal callback that starts the cycle of this controller. | ||
64 | - void _onStart() { | 43 | + /// Called at the exact moment the widget is allocated in memory. |
44 | + /// It uses an internal "callable" type, to avoid any @overrides in subclases. | ||
45 | + /// This method should be internal and is required to define the | ||
46 | + /// lifetime cycle of the subclass. | ||
47 | + // @protected | ||
48 | + @mustCallSuper | ||
49 | + @nonVirtual | ||
50 | + void onStart() { | ||
51 | + // _checkIfAlreadyConfigured(); | ||
65 | if (_initialized) return; | 52 | if (_initialized) return; |
66 | onInit(); | 53 | onInit(); |
67 | _initialized = true; | 54 | _initialized = true; |
@@ -72,33 +59,31 @@ mixin GetLifeCycleBase { | @@ -72,33 +59,31 @@ mixin GetLifeCycleBase { | ||
72 | /// Checks whether the controller has already been closed. | 59 | /// Checks whether the controller has already been closed. |
73 | bool get isClosed => _isClosed; | 60 | bool get isClosed => _isClosed; |
74 | 61 | ||
75 | - // Internal callback that starts the cycle of this controller. | ||
76 | - void _onDelete() { | 62 | + // Called when the controller is removed from memory. |
63 | + @mustCallSuper | ||
64 | + @nonVirtual | ||
65 | + void onDelete() { | ||
77 | if (_isClosed) return; | 66 | if (_isClosed) return; |
78 | _isClosed = true; | 67 | _isClosed = true; |
79 | onClose(); | 68 | onClose(); |
80 | } | 69 | } |
81 | 70 | ||
82 | - void $configureLifeCycle() { | ||
83 | - _checkIfAlreadyConfigured(); | ||
84 | - onStart._callback = _onStart; | ||
85 | - onDelete._callback = _onDelete; | ||
86 | - } | ||
87 | - | ||
88 | - void _checkIfAlreadyConfigured() { | ||
89 | - if (_initialized) { | ||
90 | - throw """You can only call configureLifeCycle once. | ||
91 | -The proper place to insert it is in your class's constructor | ||
92 | -that inherits GetLifeCycle."""; | ||
93 | - } | ||
94 | - } | ||
95 | -} | ||
96 | - | ||
97 | -abstract class GetLifeCycle with GetLifeCycleBase { | ||
98 | - GetLifeCycle() { | ||
99 | - $configureLifeCycle(); | ||
100 | - } | 71 | +// void _checkIfAlreadyConfigured() { |
72 | +// if (_initialized) { | ||
73 | +// throw """You can only call configureLifeCycle once. | ||
74 | +// The proper place to insert it is in your class's constructor | ||
75 | +// that inherits GetLifeCycle."""; | ||
76 | +// } | ||
77 | +// } | ||
101 | } | 78 | } |
102 | 79 | ||
103 | /// Allow track difference between GetxServices and GetxControllers | 80 | /// Allow track difference between GetxServices and GetxControllers |
104 | mixin GetxServiceMixin {} | 81 | mixin GetxServiceMixin {} |
82 | + | ||
83 | +/// Unlike GetxController, which serves to control events on each of its pages, | ||
84 | +/// GetxService is not automatically disposed (nor can be removed with | ||
85 | +/// Get.delete()). | ||
86 | +/// It is ideal for situations where, once started, that service will | ||
87 | +/// remain in memory, such as Auth control for example. Only way to remove | ||
88 | +/// it is Get.reset(). | ||
89 | +abstract class GetxService with GetLifeCycleMixin, GetxServiceMixin {} |
@@ -2,10 +2,6 @@ library get_navigation; | @@ -2,10 +2,6 @@ library get_navigation; | ||
2 | 2 | ||
3 | export 'src/bottomsheet/bottomsheet.dart'; | 3 | 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'; | ||
6 | -export 'src/nav2/get_nav_config.dart'; | ||
7 | -export 'src/nav2/get_router_delegate.dart'; | ||
8 | -export 'src/nav2/router_outlet.dart'; | ||
9 | export 'src/root/get_cupertino_app.dart'; | 5 | export 'src/root/get_cupertino_app.dart'; |
10 | export 'src/root/get_material_app.dart'; | 6 | export 'src/root/get_material_app.dart'; |
11 | export 'src/root/internacionalization.dart'; | 7 | export 'src/root/internacionalization.dart'; |
@@ -13,6 +9,7 @@ export 'src/root/root_controller.dart'; | @@ -13,6 +9,7 @@ export 'src/root/root_controller.dart'; | ||
13 | export 'src/routes/custom_transition.dart'; | 9 | export 'src/routes/custom_transition.dart'; |
14 | export 'src/routes/default_route.dart'; | 10 | export 'src/routes/default_route.dart'; |
15 | export 'src/routes/get_route.dart'; | 11 | export 'src/routes/get_route.dart'; |
12 | +export 'src/routes/index.dart'; | ||
16 | export 'src/routes/observers/route_observer.dart'; | 13 | export 'src/routes/observers/route_observer.dart'; |
17 | export 'src/routes/route_middleware.dart'; | 14 | export 'src/routes/route_middleware.dart'; |
18 | export 'src/routes/transitions_type.dart'; | 15 | export 'src/routes/transitions_type.dart'; |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | + | ||
2 | import '../../../get.dart'; | 3 | import '../../../get.dart'; |
3 | import '../router_report.dart'; | 4 | import '../router_report.dart'; |
4 | 5 | ||
@@ -21,7 +22,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | @@ -21,7 +22,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | ||
21 | this.enterBottomSheetDuration = const Duration(milliseconds: 250), | 22 | this.enterBottomSheetDuration = const Duration(milliseconds: 250), |
22 | this.exitBottomSheetDuration = const Duration(milliseconds: 200), | 23 | this.exitBottomSheetDuration = const Duration(milliseconds: 200), |
23 | }) : super(settings: settings) { | 24 | }) : super(settings: settings) { |
24 | - RouterReportManager.reportCurrentRoute(this); | 25 | + RouterReportManager.instance.reportCurrentRoute(this); |
25 | } | 26 | } |
26 | final bool? isPersistent; | 27 | final bool? isPersistent; |
27 | final WidgetBuilder? builder; | 28 | final WidgetBuilder? builder; |
@@ -56,7 +57,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | @@ -56,7 +57,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | ||
56 | 57 | ||
57 | @override | 58 | @override |
58 | void dispose() { | 59 | void dispose() { |
59 | - RouterReportManager.reportRouteDispose(this); | 60 | + RouterReportManager.instance.reportRouteDispose(this); |
60 | super.dispose(); | 61 | super.dispose(); |
61 | } | 62 | } |
62 | 63 |
1 | import 'package:flutter/widgets.dart'; | 1 | import 'package:flutter/widgets.dart'; |
2 | + | ||
2 | import '../router_report.dart'; | 3 | import '../router_report.dart'; |
3 | 4 | ||
4 | class GetDialogRoute<T> extends PopupRoute<T> { | 5 | class GetDialogRoute<T> extends PopupRoute<T> { |
@@ -17,7 +18,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | @@ -17,7 +18,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | ||
17 | _transitionDuration = transitionDuration, | 18 | _transitionDuration = transitionDuration, |
18 | _transitionBuilder = transitionBuilder, | 19 | _transitionBuilder = transitionBuilder, |
19 | super(settings: settings) { | 20 | super(settings: settings) { |
20 | - RouterReportManager.reportCurrentRoute(this); | 21 | + RouterReportManager.instance.reportCurrentRoute(this); |
21 | } | 22 | } |
22 | 23 | ||
23 | final RoutePageBuilder widget; | 24 | final RoutePageBuilder widget; |
@@ -28,7 +29,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | @@ -28,7 +29,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | ||
28 | 29 | ||
29 | @override | 30 | @override |
30 | void dispose() { | 31 | void dispose() { |
31 | - RouterReportManager.reportRouteDispose(this); | 32 | + RouterReportManager.instance.reportRouteDispose(this); |
32 | super.dispose(); | 33 | super.dispose(); |
33 | } | 34 | } |
34 | 35 |
@@ -8,15 +8,11 @@ import '../../get_instance/src/bindings_interface.dart'; | @@ -8,15 +8,11 @@ import '../../get_instance/src/bindings_interface.dart'; | ||
8 | import '../../get_utils/get_utils.dart'; | 8 | import '../../get_utils/get_utils.dart'; |
9 | import '../get_navigation.dart'; | 9 | import '../get_navigation.dart'; |
10 | import 'dialog/dialog_route.dart'; | 10 | import 'dialog/dialog_route.dart'; |
11 | -import 'root/parse_route.dart'; | ||
12 | -import 'root/root_controller.dart'; | ||
13 | -import 'routes/transitions_type.dart'; | ||
14 | -import 'snackbar/snackbar_controller.dart'; | ||
15 | 11 | ||
16 | /// It replaces the Flutter Navigator, but needs no context. | 12 | /// It replaces the Flutter Navigator, but needs no context. |
17 | /// You can to use navigator.push(YourRoute()) rather | 13 | /// You can to use navigator.push(YourRoute()) rather |
18 | /// Navigator.push(context, YourRoute()); | 14 | /// Navigator.push(context, YourRoute()); |
19 | -NavigatorState? get navigator => GetNavigation(Get).key.currentState; | 15 | +NavigatorState? get navigator => GetNavigationExt(Get).key.currentState; |
20 | 16 | ||
21 | extension ExtensionBottomSheet on GetInterface { | 17 | extension ExtensionBottomSheet on GetInterface { |
22 | Future<T?> bottomSheet<T>( | 18 | Future<T?> bottomSheet<T>( |
@@ -80,6 +76,7 @@ extension ExtensionDialog on GetInterface { | @@ -80,6 +76,7 @@ extension ExtensionDialog on GetInterface { | ||
80 | Curve? transitionCurve, | 76 | Curve? transitionCurve, |
81 | String? name, | 77 | String? name, |
82 | RouteSettings? routeSettings, | 78 | RouteSettings? routeSettings, |
79 | + String? id, | ||
83 | }) { | 80 | }) { |
84 | assert(debugCheckHasMaterialLocalizations(context!)); | 81 | assert(debugCheckHasMaterialLocalizations(context!)); |
85 | 82 | ||
@@ -112,12 +109,13 @@ extension ExtensionDialog on GetInterface { | @@ -112,12 +109,13 @@ extension ExtensionDialog on GetInterface { | ||
112 | navigatorKey: navigatorKey, | 109 | navigatorKey: navigatorKey, |
113 | routeSettings: | 110 | routeSettings: |
114 | routeSettings ?? RouteSettings(arguments: arguments, name: name), | 111 | routeSettings ?? RouteSettings(arguments: arguments, name: name), |
112 | + id: id, | ||
115 | ); | 113 | ); |
116 | } | 114 | } |
117 | 115 | ||
118 | /// Api from showGeneralDialog with no context | 116 | /// Api from showGeneralDialog with no context |
119 | - Future<T?> generalDialog<T>({ | ||
120 | - required RoutePageBuilder pageBuilder, | 117 | + Future<T?> generalDialog<T>( |
118 | + {required RoutePageBuilder pageBuilder, | ||
121 | bool barrierDismissible = false, | 119 | bool barrierDismissible = false, |
122 | String? barrierLabel, | 120 | String? barrierLabel, |
123 | Color barrierColor = const Color(0x80000000), | 121 | Color barrierColor = const Color(0x80000000), |
@@ -125,9 +123,10 @@ extension ExtensionDialog on GetInterface { | @@ -125,9 +123,10 @@ extension ExtensionDialog on GetInterface { | ||
125 | RouteTransitionsBuilder? transitionBuilder, | 123 | RouteTransitionsBuilder? transitionBuilder, |
126 | GlobalKey<NavigatorState>? navigatorKey, | 124 | GlobalKey<NavigatorState>? navigatorKey, |
127 | RouteSettings? routeSettings, | 125 | RouteSettings? routeSettings, |
128 | - }) { | 126 | + String? id}) { |
129 | assert(!barrierDismissible || barrierLabel != null); | 127 | assert(!barrierDismissible || barrierLabel != null); |
130 | - final nav = navigatorKey?.currentState ?? | 128 | + final key = navigatorKey ?? Get.nestedKey(id)?.navigatorKey; |
129 | + final nav = key?.currentState ?? | ||
131 | Navigator.of(overlayContext!, | 130 | Navigator.of(overlayContext!, |
132 | rootNavigator: | 131 | rootNavigator: |
133 | true); //overlay context will always return the root navigator | 132 | true); //overlay context will always return the root navigator |
@@ -150,6 +149,7 @@ extension ExtensionDialog on GetInterface { | @@ -150,6 +149,7 @@ extension ExtensionDialog on GetInterface { | ||
150 | EdgeInsetsGeometry? titlePadding, | 149 | EdgeInsetsGeometry? titlePadding, |
151 | TextStyle? titleStyle, | 150 | TextStyle? titleStyle, |
152 | Widget? content, | 151 | Widget? content, |
152 | + String? id, | ||
153 | EdgeInsetsGeometry? contentPadding, | 153 | EdgeInsetsGeometry? contentPadding, |
154 | VoidCallback? onConfirm, | 154 | VoidCallback? onConfirm, |
155 | VoidCallback? onCancel, | 155 | VoidCallback? onCancel, |
@@ -194,7 +194,7 @@ extension ExtensionDialog on GetInterface { | @@ -194,7 +194,7 @@ extension ExtensionDialog on GetInterface { | ||
194 | color: buttonColor ?? theme.colorScheme.secondary, | 194 | color: buttonColor ?? theme.colorScheme.secondary, |
195 | width: 2, | 195 | width: 2, |
196 | style: BorderStyle.solid), | 196 | style: BorderStyle.solid), |
197 | - borderRadius: BorderRadius.circular(100)), | 197 | + borderRadius: BorderRadius.circular(radius)), |
198 | ), | 198 | ), |
199 | onPressed: () { | 199 | onPressed: () { |
200 | onCancel?.call(); | 200 | onCancel?.call(); |
@@ -217,7 +217,7 @@ extension ExtensionDialog on GetInterface { | @@ -217,7 +217,7 @@ extension ExtensionDialog on GetInterface { | ||
217 | tapTargetSize: MaterialTapTargetSize.shrinkWrap, | 217 | tapTargetSize: MaterialTapTargetSize.shrinkWrap, |
218 | backgroundColor: buttonColor ?? theme.colorScheme.secondary, | 218 | backgroundColor: buttonColor ?? theme.colorScheme.secondary, |
219 | shape: RoundedRectangleBorder( | 219 | shape: RoundedRectangleBorder( |
220 | - borderRadius: BorderRadius.circular(100)), | 220 | + borderRadius: BorderRadius.circular(radius)), |
221 | ), | 221 | ), |
222 | child: Text( | 222 | child: Text( |
223 | textConfirm ?? "Ok", | 223 | textConfirm ?? "Ok", |
@@ -271,6 +271,7 @@ extension ExtensionDialog on GetInterface { | @@ -271,6 +271,7 @@ extension ExtensionDialog on GetInterface { | ||
271 | : baseAlertDialog, | 271 | : baseAlertDialog, |
272 | barrierDismissible: barrierDismissible, | 272 | barrierDismissible: barrierDismissible, |
273 | navigatorKey: navigatorKey, | 273 | navigatorKey: navigatorKey, |
274 | + id: id, | ||
274 | ); | 275 | ); |
275 | } | 276 | } |
276 | } | 277 | } |
@@ -357,7 +358,7 @@ extension ExtensionSnackbar on GetInterface { | @@ -357,7 +358,7 @@ extension ExtensionSnackbar on GetInterface { | ||
357 | if (instantInit) { | 358 | if (instantInit) { |
358 | controller.show(); | 359 | controller.show(); |
359 | } else { | 360 | } else { |
360 | - SchedulerBinding.instance!.addPostFrameCallback((_) { | 361 | + ambiguate(SchedulerBinding.instance)!.addPostFrameCallback((_) { |
361 | controller.show(); | 362 | controller.show(); |
362 | }); | 363 | }); |
363 | } | 364 | } |
@@ -468,7 +469,7 @@ extension ExtensionSnackbar on GetInterface { | @@ -468,7 +469,7 @@ extension ExtensionSnackbar on GetInterface { | ||
468 | controller.show(); | 469 | controller.show(); |
469 | } else { | 470 | } else { |
470 | //routing.isSnackbar = true; | 471 | //routing.isSnackbar = true; |
471 | - SchedulerBinding.instance!.addPostFrameCallback((_) { | 472 | + ambiguate(SchedulerBinding.instance)!.addPostFrameCallback((_) { |
472 | controller.show(); | 473 | controller.show(); |
473 | }); | 474 | }); |
474 | } | 475 | } |
@@ -476,7 +477,7 @@ extension ExtensionSnackbar on GetInterface { | @@ -476,7 +477,7 @@ extension ExtensionSnackbar on GetInterface { | ||
476 | } | 477 | } |
477 | } | 478 | } |
478 | 479 | ||
479 | -extension GetNavigation on GetInterface { | 480 | +extension GetNavigationExt on GetInterface { |
480 | /// **Navigation.push()** shortcut.<br><br> | 481 | /// **Navigation.push()** shortcut.<br><br> |
481 | /// | 482 | /// |
482 | /// Pushes a new `page` to the stack | 483 | /// Pushes a new `page` to the stack |
@@ -501,9 +502,8 @@ extension GetNavigation on GetInterface { | @@ -501,9 +502,8 @@ extension GetNavigation on GetInterface { | ||
501 | /// | 502 | /// |
502 | /// By default, GetX will prevent you from push a route that you already in, | 503 | /// By default, GetX will prevent you from push a route that you already in, |
503 | /// if you want to push anyway, set [preventDuplicates] to false | 504 | /// if you want to push anyway, set [preventDuplicates] to false |
504 | - Future<T?>? to<T>( | ||
505 | - dynamic page, { | ||
506 | - bool? opaque, | 505 | + Future<T?>? to<T>(Widget Function() page, |
506 | + {bool? opaque, | ||
507 | Transition? transition, | 507 | Transition? transition, |
508 | Curve? curve, | 508 | Curve? curve, |
509 | Duration? duration, | 509 | Duration? duration, |
@@ -511,54 +511,53 @@ extension GetNavigation on GetInterface { | @@ -511,54 +511,53 @@ extension GetNavigation on GetInterface { | ||
511 | String? routeName, | 511 | String? routeName, |
512 | bool fullscreenDialog = false, | 512 | bool fullscreenDialog = false, |
513 | dynamic arguments, | 513 | dynamic arguments, |
514 | - Bindings? binding, | 514 | + List<BindingsInterface> bindings = const [], |
515 | bool preventDuplicates = true, | 515 | bool preventDuplicates = true, |
516 | bool? popGesture, | 516 | bool? popGesture, |
517 | + bool showCupertinoParallax = true, | ||
517 | double Function(BuildContext context)? gestureWidth, | 518 | double Function(BuildContext context)? gestureWidth, |
518 | - }) { | ||
519 | - // var routeName = "/${page.runtimeType}"; | ||
520 | - routeName ??= "/${page.runtimeType}"; | ||
521 | - routeName = _cleanRouteName(routeName); | ||
522 | - if (preventDuplicates && routeName == currentRoute) { | ||
523 | - return null; | ||
524 | - } | ||
525 | - return global(id).currentState?.push<T>( | ||
526 | - GetPageRoute<T>( | ||
527 | - opaque: opaque ?? true, | ||
528 | - page: _resolvePage(page, 'to'), | 519 | + bool rebuildStack = true, |
520 | + PreventDuplicateHandlingMode preventDuplicateHandlingMode = | ||
521 | + PreventDuplicateHandlingMode.ReorderRoutes}) { | ||
522 | + return searchDelegate(id).to( | ||
523 | + page, | ||
524 | + opaque: opaque, | ||
525 | + transition: transition, | ||
526 | + curve: curve, | ||
527 | + duration: duration, | ||
528 | + id: id, | ||
529 | routeName: routeName, | 529 | routeName: routeName, |
530 | - gestureWidth: gestureWidth, | ||
531 | - settings: RouteSettings( | ||
532 | - name: routeName, | ||
533 | - arguments: arguments, | ||
534 | - ), | ||
535 | - popGesture: popGesture ?? defaultPopGesture, | ||
536 | - transition: transition ?? defaultTransition, | ||
537 | - curve: curve ?? defaultTransitionCurve, | ||
538 | fullscreenDialog: fullscreenDialog, | 530 | fullscreenDialog: fullscreenDialog, |
539 | - binding: binding, | ||
540 | - transitionDuration: duration ?? defaultTransitionDuration, | ||
541 | - ), | 531 | + arguments: arguments, |
532 | + bindings: bindings, | ||
533 | + preventDuplicates: preventDuplicates, | ||
534 | + popGesture: popGesture, | ||
535 | + showCupertinoParallax: showCupertinoParallax, | ||
536 | + gestureWidth: gestureWidth, | ||
537 | + rebuildStack: rebuildStack, | ||
538 | + preventDuplicateHandlingMode: preventDuplicateHandlingMode, | ||
542 | ); | 539 | ); |
543 | } | 540 | } |
544 | 541 | ||
545 | - GetPageBuilder _resolvePage(dynamic page, String method) { | ||
546 | - if (page is GetPageBuilder) { | ||
547 | - return page; | ||
548 | - } else if (page is Widget) { | ||
549 | - Get.log( | ||
550 | - '''WARNING, consider using: "Get.$method(() => Page())" instead of "Get.$method(Page())". | ||
551 | -Using a widget function instead of a widget fully guarantees that the widget and its controllers will be removed from memory when they are no longer used. | ||
552 | - '''); | ||
553 | - return () => page; | ||
554 | - } else if (page is String) { | ||
555 | - throw '''Unexpected String, | ||
556 | -use toNamed() instead'''; | ||
557 | - } else { | ||
558 | - throw '''Unexpected format, | ||
559 | -you can only use widgets and widget functions here'''; | ||
560 | - } | ||
561 | - } | 542 | +// GetPageBuilder _resolvePage(dynamic page, String method) { |
543 | +// if (page is GetPageBuilder) { | ||
544 | +// return page; | ||
545 | +// } else if (page is Widget) { | ||
546 | +// Get.log( | ||
547 | +// '''WARNING, consider using: "Get.$method(() => Page())" | ||
548 | +//instead of "Get.$method(Page())". | ||
549 | +// Using a widget function instead of a widget fully guarantees that the widget | ||
550 | +//and its controllers will be removed from memory when they are no longer used. | ||
551 | +// '''); | ||
552 | +// return () => page; | ||
553 | +// } else if (page is String) { | ||
554 | +// throw '''Unexpected String, | ||
555 | +// use toNamed() instead'''; | ||
556 | +// } else { | ||
557 | +// throw '''Unexpected format, | ||
558 | +// you can only use widgets and widget functions here'''; | ||
559 | +// } | ||
560 | +// } | ||
562 | 561 | ||
563 | /// **Navigation.pushNamed()** shortcut.<br><br> | 562 | /// **Navigation.pushNamed()** shortcut.<br><br> |
564 | /// | 563 | /// |
@@ -579,22 +578,25 @@ you can only use widgets and widget functions here'''; | @@ -579,22 +578,25 @@ you can only use widgets and widget functions here'''; | ||
579 | Future<T?>? toNamed<T>( | 578 | Future<T?>? toNamed<T>( |
580 | String page, { | 579 | String page, { |
581 | dynamic arguments, | 580 | dynamic arguments, |
582 | - int? id, | 581 | + dynamic id, |
583 | bool preventDuplicates = true, | 582 | bool preventDuplicates = true, |
584 | Map<String, String>? parameters, | 583 | Map<String, String>? parameters, |
585 | }) { | 584 | }) { |
586 | - if (preventDuplicates && page == currentRoute) { | ||
587 | - return null; | ||
588 | - } | 585 | + // if (preventDuplicates && page == currentRoute) { |
586 | + // return null; | ||
587 | + // } | ||
589 | 588 | ||
590 | if (parameters != null) { | 589 | if (parameters != null) { |
591 | final uri = Uri(path: page, queryParameters: parameters); | 590 | final uri = Uri(path: page, queryParameters: parameters); |
592 | page = uri.toString(); | 591 | page = uri.toString(); |
593 | } | 592 | } |
594 | 593 | ||
595 | - return global(id).currentState?.pushNamed<T>( | 594 | + return searchDelegate(id).toNamed( |
596 | page, | 595 | page, |
597 | arguments: arguments, | 596 | arguments: arguments, |
597 | + id: id, | ||
598 | + preventDuplicates: preventDuplicates, | ||
599 | + parameters: parameters, | ||
598 | ); | 600 | ); |
599 | } | 601 | } |
600 | 602 | ||
@@ -618,20 +620,22 @@ you can only use widgets and widget functions here'''; | @@ -618,20 +620,22 @@ you can only use widgets and widget functions here'''; | ||
618 | String page, { | 620 | String page, { |
619 | dynamic arguments, | 621 | dynamic arguments, |
620 | int? id, | 622 | int? id, |
621 | - bool preventDuplicates = true, | ||
622 | Map<String, String>? parameters, | 623 | Map<String, String>? parameters, |
623 | }) { | 624 | }) { |
624 | - if (preventDuplicates && page == currentRoute) { | ||
625 | - return null; | ||
626 | - } | 625 | + // if (preventDuplicates && page == currentRoute) { |
626 | + // return null; | ||
627 | + // } | ||
627 | 628 | ||
628 | if (parameters != null) { | 629 | if (parameters != null) { |
629 | final uri = Uri(path: page, queryParameters: parameters); | 630 | final uri = Uri(path: page, queryParameters: parameters); |
630 | page = uri.toString(); | 631 | page = uri.toString(); |
631 | } | 632 | } |
632 | - return global(id).currentState?.pushReplacementNamed( | 633 | + return searchDelegate(id).offNamed( |
633 | page, | 634 | page, |
634 | arguments: arguments, | 635 | arguments: arguments, |
636 | + id: id, | ||
637 | + // preventDuplicates: preventDuplicates, | ||
638 | + parameters: parameters, | ||
635 | ); | 639 | ); |
636 | } | 640 | } |
637 | 641 | ||
@@ -648,34 +652,10 @@ you can only use widgets and widget functions here'''; | @@ -648,34 +652,10 @@ you can only use widgets and widget functions here'''; | ||
648 | /// or also like this: | 652 | /// or also like this: |
649 | /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the | 653 | /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the |
650 | /// dialog is closed | 654 | /// dialog is closed |
651 | - void until(RoutePredicate predicate, {int? id}) { | 655 | + void until(bool Function(GetPage<dynamic>) predicate, {int? id}) { |
652 | // if (key.currentState.mounted) // add this if appear problems on future with route navigate | 656 | // if (key.currentState.mounted) // add this if appear problems on future with route navigate |
653 | // when widget don't mounted | 657 | // when widget don't mounted |
654 | - return global(id).currentState?.popUntil(predicate); | ||
655 | - } | ||
656 | - | ||
657 | - /// **Navigation.pushAndRemoveUntil()** shortcut.<br><br> | ||
658 | - /// | ||
659 | - /// Push the given `page`, and then pop several pages in the stack until | ||
660 | - /// [predicate] returns true | ||
661 | - /// | ||
662 | - /// [id] is for when you are using nested navigation, | ||
663 | - /// as explained in documentation | ||
664 | - /// | ||
665 | - /// Obs: unlike other get methods, this one you need to send a function | ||
666 | - /// that returns the widget to the page argument, like this: | ||
667 | - /// Get.offUntil(GetPageRoute(page: () => HomePage()), predicate) | ||
668 | - /// | ||
669 | - /// [predicate] can be used like this: | ||
670 | - /// `Get.offUntil(page, (route) => (route as GetPageRoute).routeName == '/home')` | ||
671 | - /// to pop routes in stack until home, | ||
672 | - /// or also like this: | ||
673 | - /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the dialog | ||
674 | - /// is closed | ||
675 | - Future<T?>? offUntil<T>(Route<T> page, RoutePredicate predicate, {int? id}) { | ||
676 | - // if (key.currentState.mounted) // add this if appear problems on future with route navigate | ||
677 | - // when widget don't mounted | ||
678 | - return global(id).currentState?.pushAndRemoveUntil<T>(page, predicate); | 658 | + return searchDelegate(id).backUntil(predicate); |
679 | } | 659 | } |
680 | 660 | ||
681 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> | 661 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> |
@@ -698,7 +678,7 @@ you can only use widgets and widget functions here'''; | @@ -698,7 +678,7 @@ you can only use widgets and widget functions here'''; | ||
698 | /// Note: Always put a slash on the route name ('/page1'), to avoid unexpected errors | 678 | /// Note: Always put a slash on the route name ('/page1'), to avoid unexpected errors |
699 | Future<T?>? offNamedUntil<T>( | 679 | Future<T?>? offNamedUntil<T>( |
700 | String page, | 680 | String page, |
701 | - RoutePredicate predicate, { | 681 | + bool Function(GetPage<dynamic>)? predicate, { |
702 | int? id, | 682 | int? id, |
703 | dynamic arguments, | 683 | dynamic arguments, |
704 | Map<String, String>? parameters, | 684 | Map<String, String>? parameters, |
@@ -708,10 +688,12 @@ you can only use widgets and widget functions here'''; | @@ -708,10 +688,12 @@ you can only use widgets and widget functions here'''; | ||
708 | page = uri.toString(); | 688 | page = uri.toString(); |
709 | } | 689 | } |
710 | 690 | ||
711 | - return global(id).currentState?.pushNamedAndRemoveUntil<T>( | 691 | + return searchDelegate(id).offNamedUntil<T>( |
712 | page, | 692 | page, |
713 | - predicate, | 693 | + predicate: predicate, |
694 | + id: id, | ||
714 | arguments: arguments, | 695 | arguments: arguments, |
696 | + parameters: parameters, | ||
715 | ); | 697 | ); |
716 | } | 698 | } |
717 | 699 | ||
@@ -737,7 +719,7 @@ you can only use widgets and widget functions here'''; | @@ -737,7 +719,7 @@ you can only use widgets and widget functions here'''; | ||
737 | final uri = Uri(path: page, queryParameters: parameters); | 719 | final uri = Uri(path: page, queryParameters: parameters); |
738 | page = uri.toString(); | 720 | page = uri.toString(); |
739 | } | 721 | } |
740 | - return global(id).currentState?.popAndPushNamed( | 722 | + return searchDelegate(id).backAndtoNamed( |
741 | page, | 723 | page, |
742 | arguments: arguments, | 724 | arguments: arguments, |
743 | result: result, | 725 | result: result, |
@@ -750,8 +732,8 @@ you can only use widgets and widget functions here'''; | @@ -750,8 +732,8 @@ you can only use widgets and widget functions here'''; | ||
750 | /// | 732 | /// |
751 | /// [id] is for when you are using nested navigation, | 733 | /// [id] is for when you are using nested navigation, |
752 | /// as explained in documentation | 734 | /// as explained in documentation |
753 | - void removeRoute(Route<dynamic> route, {int? id}) { | ||
754 | - return global(id).currentState?.removeRoute(route); | 735 | + void removeRoute(String name, {int? id}) { |
736 | + return searchDelegate(id).removeRoute(name); | ||
755 | } | 737 | } |
756 | 738 | ||
757 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> | 739 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> |
@@ -776,7 +758,7 @@ you can only use widgets and widget functions here'''; | @@ -776,7 +758,7 @@ you can only use widgets and widget functions here'''; | ||
776 | /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors | 758 | /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors |
777 | Future<T?>? offAllNamed<T>( | 759 | Future<T?>? offAllNamed<T>( |
778 | String newRouteName, { | 760 | String newRouteName, { |
779 | - RoutePredicate? predicate, | 761 | + // bool Function(GetPage<dynamic>)? predicate, |
780 | dynamic arguments, | 762 | dynamic arguments, |
781 | int? id, | 763 | int? id, |
782 | Map<String, String>? parameters, | 764 | Map<String, String>? parameters, |
@@ -786,10 +768,12 @@ you can only use widgets and widget functions here'''; | @@ -786,10 +768,12 @@ you can only use widgets and widget functions here'''; | ||
786 | newRouteName = uri.toString(); | 768 | newRouteName = uri.toString(); |
787 | } | 769 | } |
788 | 770 | ||
789 | - return global(id).currentState?.pushNamedAndRemoveUntil<T>( | 771 | + return searchDelegate(id).offAllNamed<T>( |
790 | newRouteName, | 772 | newRouteName, |
791 | - predicate ?? (_) => false, | 773 | + //predicate: predicate ?? (_) => false, |
792 | arguments: arguments, | 774 | arguments: arguments, |
775 | + id: id, | ||
776 | + parameters: parameters, | ||
793 | ); | 777 | ); |
794 | } | 778 | } |
795 | 779 | ||
@@ -819,6 +803,13 @@ you can only use widgets and widget functions here'''; | @@ -819,6 +803,13 @@ you can only use widgets and widget functions here'''; | ||
819 | bool canPop = true, | 803 | bool canPop = true, |
820 | int? id, | 804 | int? id, |
821 | }) { | 805 | }) { |
806 | + //TODO: remove this when change own api to Dialog and BottomSheets | ||
807 | + //to declarative way | ||
808 | + if (isDialogOpen! || isBottomSheetOpen!) { | ||
809 | + searchDelegate(id).navigatorKey.currentState?.pop(); | ||
810 | + return; | ||
811 | + } | ||
812 | + | ||
822 | //TODO: This code brings compatibility of the new snackbar with GetX 4, | 813 | //TODO: This code brings compatibility of the new snackbar with GetX 4, |
823 | // remove this code in version 5 | 814 | // remove this code in version 5 |
824 | if (isSnackbarOpen && !closeOverlays) { | 815 | if (isSnackbarOpen && !closeOverlays) { |
@@ -832,16 +823,21 @@ you can only use widgets and widget functions here'''; | @@ -832,16 +823,21 @@ you can only use widgets and widget functions here'''; | ||
832 | if (isSnackbarOpen) { | 823 | if (isSnackbarOpen) { |
833 | closeAllSnackbars(); | 824 | closeAllSnackbars(); |
834 | } | 825 | } |
835 | - navigator?.popUntil((route) { | ||
836 | - return (!isDialogOpen! && !isBottomSheetOpen!); | ||
837 | - }); | 826 | + |
827 | + while ((isDialogOpen! && isBottomSheetOpen!)) { | ||
828 | + searchDelegate(id).navigatorKey.currentState?.pop(); | ||
829 | + } | ||
830 | + | ||
831 | + // navigator?.popUntil((route) { | ||
832 | + // return; | ||
833 | + // }); | ||
838 | } | 834 | } |
839 | if (canPop) { | 835 | if (canPop) { |
840 | - if (global(id).currentState?.canPop() == true) { | ||
841 | - global(id).currentState?.pop<T>(result); | 836 | + if (searchDelegate(id).canBack == true) { |
837 | + searchDelegate(id).back<T>(result); | ||
842 | } | 838 | } |
843 | } else { | 839 | } else { |
844 | - global(id).currentState?.pop<T>(result); | 840 | + searchDelegate(id).back<T>(result); |
845 | } | 841 | } |
846 | } | 842 | } |
847 | 843 | ||
@@ -856,7 +852,7 @@ you can only use widgets and widget functions here'''; | @@ -856,7 +852,7 @@ you can only use widgets and widget functions here'''; | ||
856 | times = 1; | 852 | times = 1; |
857 | } | 853 | } |
858 | var count = 0; | 854 | var count = 0; |
859 | - var back = global(id).currentState?.popUntil((route) => count++ == times); | 855 | + var back = searchDelegate(id).backUntil((route) => count++ == times); |
860 | 856 | ||
861 | return back; | 857 | return back; |
862 | } | 858 | } |
@@ -887,15 +883,15 @@ you can only use widgets and widget functions here'''; | @@ -887,15 +883,15 @@ you can only use widgets and widget functions here'''; | ||
887 | /// By default, GetX will prevent you from push a route that you already in, | 883 | /// By default, GetX will prevent you from push a route that you already in, |
888 | /// if you want to push anyway, set [preventDuplicates] to false | 884 | /// if you want to push anyway, set [preventDuplicates] to false |
889 | Future<T?>? off<T>( | 885 | Future<T?>? off<T>( |
890 | - dynamic page, { | ||
891 | - bool opaque = false, | 886 | + Widget Function() page, { |
887 | + bool? opaque, | ||
892 | Transition? transition, | 888 | Transition? transition, |
893 | Curve? curve, | 889 | Curve? curve, |
894 | bool? popGesture, | 890 | bool? popGesture, |
895 | int? id, | 891 | int? id, |
896 | String? routeName, | 892 | String? routeName, |
897 | dynamic arguments, | 893 | dynamic arguments, |
898 | - Bindings? binding, | 894 | + List<BindingsInterface> bindings = const [], |
899 | bool fullscreenDialog = false, | 895 | bool fullscreenDialog = false, |
900 | bool preventDuplicates = true, | 896 | bool preventDuplicates = true, |
901 | Duration? duration, | 897 | Duration? duration, |
@@ -906,21 +902,34 @@ you can only use widgets and widget functions here'''; | @@ -906,21 +902,34 @@ you can only use widgets and widget functions here'''; | ||
906 | if (preventDuplicates && routeName == currentRoute) { | 902 | if (preventDuplicates && routeName == currentRoute) { |
907 | return null; | 903 | return null; |
908 | } | 904 | } |
909 | - return global(id).currentState?.pushReplacement(GetPageRoute( | ||
910 | - opaque: opaque, | ||
911 | - gestureWidth: gestureWidth, | ||
912 | - page: _resolvePage(page, 'off'), | ||
913 | - binding: binding, | ||
914 | - settings: RouteSettings( | ||
915 | - arguments: arguments, | ||
916 | - name: routeName, | ||
917 | - ), | 905 | + return searchDelegate(id).off( |
906 | + page, | ||
907 | + opaque: opaque ?? true, | ||
908 | + transition: transition, | ||
909 | + curve: curve, | ||
910 | + popGesture: popGesture, | ||
911 | + id: id, | ||
918 | routeName: routeName, | 912 | routeName: routeName, |
913 | + arguments: arguments, | ||
914 | + bindings: bindings, | ||
919 | fullscreenDialog: fullscreenDialog, | 915 | fullscreenDialog: fullscreenDialog, |
920 | - popGesture: popGesture ?? defaultPopGesture, | ||
921 | - transition: transition ?? defaultTransition, | ||
922 | - curve: curve ?? defaultTransitionCurve, | ||
923 | - transitionDuration: duration ?? defaultTransitionDuration)); | 916 | + preventDuplicates: preventDuplicates, |
917 | + duration: duration, | ||
918 | + gestureWidth: gestureWidth, | ||
919 | + ); | ||
920 | + } | ||
921 | + | ||
922 | + Future<T?> offUntil<T>( | ||
923 | + Widget Function() page, | ||
924 | + bool Function(GetPage) predicate, [ | ||
925 | + Object? arguments, | ||
926 | + int? id, | ||
927 | + ]) { | ||
928 | + return searchDelegate(id).offUntil( | ||
929 | + page, | ||
930 | + predicate, | ||
931 | + arguments, | ||
932 | + ); | ||
924 | } | 933 | } |
925 | 934 | ||
926 | /// | 935 | /// |
@@ -954,14 +963,14 @@ you can only use widgets and widget functions here'''; | @@ -954,14 +963,14 @@ you can only use widgets and widget functions here'''; | ||
954 | /// By default, GetX will prevent you from push a route that you already in, | 963 | /// By default, GetX will prevent you from push a route that you already in, |
955 | /// if you want to push anyway, set [preventDuplicates] to false | 964 | /// if you want to push anyway, set [preventDuplicates] to false |
956 | Future<T?>? offAll<T>( | 965 | Future<T?>? offAll<T>( |
957 | - dynamic page, { | ||
958 | - RoutePredicate? predicate, | ||
959 | - bool opaque = false, | 966 | + Widget Function() page, { |
967 | + bool Function(GetPage<dynamic>)? predicate, | ||
968 | + bool? opaque, | ||
960 | bool? popGesture, | 969 | bool? popGesture, |
961 | int? id, | 970 | int? id, |
962 | String? routeName, | 971 | String? routeName, |
963 | dynamic arguments, | 972 | dynamic arguments, |
964 | - Bindings? binding, | 973 | + List<BindingsInterface> bindings = const [], |
965 | bool fullscreenDialog = false, | 974 | bool fullscreenDialog = false, |
966 | Transition? transition, | 975 | Transition? transition, |
967 | Curve? curve, | 976 | Curve? curve, |
@@ -970,24 +979,21 @@ you can only use widgets and widget functions here'''; | @@ -970,24 +979,21 @@ you can only use widgets and widget functions here'''; | ||
970 | }) { | 979 | }) { |
971 | routeName ??= "/${page.runtimeType.toString()}"; | 980 | routeName ??= "/${page.runtimeType.toString()}"; |
972 | routeName = _cleanRouteName(routeName); | 981 | routeName = _cleanRouteName(routeName); |
973 | - return global(id).currentState?.pushAndRemoveUntil<T>( | ||
974 | - GetPageRoute<T>( | ||
975 | - opaque: opaque, | ||
976 | - popGesture: popGesture ?? defaultPopGesture, | ||
977 | - page: _resolvePage(page, 'offAll'), | ||
978 | - binding: binding, | ||
979 | - gestureWidth: gestureWidth, | ||
980 | - settings: RouteSettings( | ||
981 | - name: routeName, | 982 | + return searchDelegate(id).offAll<T>( |
983 | + page, | ||
984 | + predicate: predicate, | ||
985 | + opaque: opaque ?? true, | ||
986 | + popGesture: popGesture, | ||
987 | + id: id, | ||
988 | + // routeName routeName, | ||
982 | arguments: arguments, | 989 | arguments: arguments, |
983 | - ), | 990 | + bindings: bindings, |
984 | fullscreenDialog: fullscreenDialog, | 991 | fullscreenDialog: fullscreenDialog, |
985 | - routeName: routeName, | ||
986 | - transition: transition ?? defaultTransition, | ||
987 | - curve: curve ?? defaultTransitionCurve, | ||
988 | - transitionDuration: duration ?? defaultTransitionDuration, | ||
989 | - ), | ||
990 | - predicate ?? (route) => false); | 992 | + transition: transition, |
993 | + curve: curve, | ||
994 | + duration: duration, | ||
995 | + gestureWidth: gestureWidth, | ||
996 | + ); | ||
991 | } | 997 | } |
992 | 998 | ||
993 | /// Takes a route [name] String generated by [to], [off], [offAll] | 999 | /// Takes a route [name] String generated by [to], [off], [offAll] |
@@ -1055,7 +1061,7 @@ you can only use widgets and widget functions here'''; | @@ -1055,7 +1061,7 @@ you can only use widgets and widget functions here'''; | ||
1055 | /// Your entire application will be rebuilt, and touch events will not | 1061 | /// Your entire application will be rebuilt, and touch events will not |
1056 | /// work until the end of rendering. | 1062 | /// work until the end of rendering. |
1057 | Future<void> forceAppUpdate() async { | 1063 | Future<void> forceAppUpdate() async { |
1058 | - await engine!.performReassemble(); | 1064 | + await engine.performReassemble(); |
1059 | } | 1065 | } |
1060 | 1066 | ||
1061 | void appUpdate() => _getxController.update(); | 1067 | void appUpdate() => _getxController.update(); |
@@ -1072,20 +1078,25 @@ you can only use widgets and widget functions here'''; | @@ -1072,20 +1078,25 @@ you can only use widgets and widget functions here'''; | ||
1072 | return _getxController.addKey(newKey); | 1078 | return _getxController.addKey(newKey); |
1073 | } | 1079 | } |
1074 | 1080 | ||
1075 | - GlobalKey<NavigatorState>? nestedKey(dynamic key) { | 1081 | + GetDelegate? nestedKey(String? key) { |
1082 | + if (key == null) { | ||
1083 | + return routerDelegate as GetDelegate; | ||
1084 | + } | ||
1076 | keys.putIfAbsent( | 1085 | keys.putIfAbsent( |
1077 | key, | 1086 | key, |
1078 | - () => GlobalKey<NavigatorState>( | ||
1079 | - debugLabel: 'Getx nested key: ${key.toString()}', | 1087 | + () => GetDelegate( |
1088 | + showHashOnUrl: true, | ||
1089 | + //debugLabel: 'Getx nested key: ${key.toString()}', | ||
1090 | + pages: RouteDecoder.fromRoute(key).currentChildrens ?? [], | ||
1080 | ), | 1091 | ), |
1081 | ); | 1092 | ); |
1082 | return keys[key]; | 1093 | return keys[key]; |
1083 | } | 1094 | } |
1084 | 1095 | ||
1085 | - GlobalKey<NavigatorState> global(int? k) { | ||
1086 | - GlobalKey<NavigatorState> _key; | 1096 | + GetDelegate searchDelegate(dynamic k) { |
1097 | + GetDelegate _key; | ||
1087 | if (k == null) { | 1098 | if (k == null) { |
1088 | - _key = key; | 1099 | + _key = Get.rootController.rootDelegate; |
1089 | } else { | 1100 | } else { |
1090 | if (!keys.containsKey(k)) { | 1101 | if (!keys.containsKey(k)) { |
1091 | throw 'Route id ($k) not found'; | 1102 | throw 'Route id ($k) not found'; |
@@ -1093,21 +1104,22 @@ you can only use widgets and widget functions here'''; | @@ -1093,21 +1104,22 @@ you can only use widgets and widget functions here'''; | ||
1093 | _key = keys[k]!; | 1104 | _key = keys[k]!; |
1094 | } | 1105 | } |
1095 | 1106 | ||
1096 | - if (_key.currentContext == null && !testMode) { | ||
1097 | - throw """You are trying to use contextless navigation without | ||
1098 | - a GetMaterialApp or Get.key. | ||
1099 | - If you are testing your app, you can use: | ||
1100 | - [Get.testMode = true], or if you are running your app on | ||
1101 | - a physical device or emulator, you must exchange your [MaterialApp] | ||
1102 | - for a [GetMaterialApp]. | ||
1103 | - """; | ||
1104 | - } | 1107 | + // if (_key.listenersLength == 0 && !testMode) { |
1108 | + // throw """You are trying to use contextless navigation without | ||
1109 | + // a GetMaterialApp or Get.key. | ||
1110 | + // If you are testing your app, you can use: | ||
1111 | + // [Get.testMode = true], or if you are running your app on | ||
1112 | + // a physical device or emulator, you must exchange your [MaterialApp] | ||
1113 | + // for a [GetMaterialApp]. | ||
1114 | + // """; | ||
1115 | + // } | ||
1105 | 1116 | ||
1106 | return _key; | 1117 | return _key; |
1107 | } | 1118 | } |
1108 | 1119 | ||
1109 | /// give current arguments | 1120 | /// give current arguments |
1110 | - dynamic get arguments => routing.args; | 1121 | + //dynamic get arguments => routing.args; |
1122 | + dynamic get arguments => _getxController.rootDelegate.arguments(); | ||
1111 | 1123 | ||
1112 | /// give name from current route | 1124 | /// give name from current route |
1113 | String get currentRoute => routing.current; | 1125 | String get currentRoute => routing.current; |
@@ -1163,12 +1175,9 @@ you can only use widgets and widget functions here'''; | @@ -1163,12 +1175,9 @@ you can only use widgets and widget functions here'''; | ||
1163 | return _theme; | 1175 | return _theme; |
1164 | } | 1176 | } |
1165 | 1177 | ||
1166 | - ///The current [WidgetsBinding] | ||
1167 | - WidgetsBinding? get engine { | ||
1168 | - if (WidgetsBinding.instance == null) { | ||
1169 | - WidgetsFlutterBinding(); | ||
1170 | - } | ||
1171 | - return WidgetsBinding.instance; | 1178 | + /// The current null safe [WidgetsBinding] |
1179 | + WidgetsBinding get engine { | ||
1180 | + return WidgetsFlutterBinding.ensureInitialized(); | ||
1172 | } | 1181 | } |
1173 | 1182 | ||
1174 | /// The window to which this binding is bound. | 1183 | /// The window to which this binding is bound. |
@@ -1225,7 +1234,7 @@ you can only use widgets and widget functions here'''; | @@ -1225,7 +1234,7 @@ you can only use widgets and widget functions here'''; | ||
1225 | 1234 | ||
1226 | GlobalKey<NavigatorState> get key => _getxController.key; | 1235 | GlobalKey<NavigatorState> get key => _getxController.key; |
1227 | 1236 | ||
1228 | - Map<dynamic, GlobalKey<NavigatorState>> get keys => _getxController.keys; | 1237 | + Map<dynamic, GetDelegate> get keys => _getxController.keys; |
1229 | 1238 | ||
1230 | GetMaterialController get rootController => _getxController; | 1239 | GetMaterialController get rootController => _getxController; |
1231 | 1240 | ||
@@ -1250,7 +1259,8 @@ you can only use widgets and widget functions here'''; | @@ -1250,7 +1259,8 @@ you can only use widgets and widget functions here'''; | ||
1250 | 1259 | ||
1251 | Routing get routing => _getxController.routing; | 1260 | Routing get routing => _getxController.routing; |
1252 | 1261 | ||
1253 | - Map<String, String?> get parameters => _getxController.parameters; | 1262 | + Map<String, String?> get parameters => |
1263 | + _getxController.rootDelegate.parameters; | ||
1254 | set parameters(Map<String, String?> newParameters) => | 1264 | set parameters(Map<String, String?> newParameters) => |
1255 | _getxController.parameters = newParameters; | 1265 | _getxController.parameters = newParameters; |
1256 | 1266 | ||
@@ -1280,10 +1290,15 @@ extension NavTwoExt on GetInterface { | @@ -1280,10 +1290,15 @@ extension NavTwoExt on GetInterface { | ||
1280 | static late final _routeTree = ParseRouteTree(routes: []); | 1290 | static late final _routeTree = ParseRouteTree(routes: []); |
1281 | 1291 | ||
1282 | ParseRouteTree get routeTree => _routeTree; | 1292 | ParseRouteTree get routeTree => _routeTree; |
1293 | + | ||
1283 | void addPage(GetPage getPage) { | 1294 | void addPage(GetPage getPage) { |
1284 | routeTree.addRoute(getPage); | 1295 | routeTree.addRoute(getPage); |
1285 | } | 1296 | } |
1286 | 1297 | ||
1298 | + void removePage(GetPage getPage) { | ||
1299 | + routeTree.removeRoute(getPage); | ||
1300 | + } | ||
1301 | + | ||
1287 | /// Casts the stored router delegate to a desired type | 1302 | /// Casts the stored router delegate to a desired type |
1288 | TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() => | 1303 | TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() => |
1289 | routerDelegate as TDelegate?; | 1304 | routerDelegate as TDelegate?; |
@@ -1307,15 +1322,15 @@ extension NavTwoExt on GetInterface { | @@ -1307,15 +1322,15 @@ extension NavTwoExt on GetInterface { | ||
1307 | 1322 | ||
1308 | // static GetDelegate? _delegate; | 1323 | // static GetDelegate? _delegate; |
1309 | 1324 | ||
1310 | - GetDelegate get rootDelegate => createDelegate(); | ||
1311 | - | ||
1312 | GetDelegate createDelegate({ | 1325 | GetDelegate createDelegate({ |
1313 | GetPage<dynamic>? notFoundRoute, | 1326 | GetPage<dynamic>? notFoundRoute, |
1327 | + List<GetPage> pages = const [], | ||
1314 | List<NavigatorObserver>? navigatorObservers, | 1328 | List<NavigatorObserver>? navigatorObservers, |
1315 | TransitionDelegate<dynamic>? transitionDelegate, | 1329 | TransitionDelegate<dynamic>? transitionDelegate, |
1316 | PopMode backButtonPopMode = PopMode.History, | 1330 | PopMode backButtonPopMode = PopMode.History, |
1317 | PreventDuplicateHandlingMode preventDuplicateHandlingMode = | 1331 | PreventDuplicateHandlingMode preventDuplicateHandlingMode = |
1318 | PreventDuplicateHandlingMode.ReorderRoutes, | 1332 | PreventDuplicateHandlingMode.ReorderRoutes, |
1333 | + GlobalKey<NavigatorState>? navigatorKey, | ||
1319 | }) { | 1334 | }) { |
1320 | if (routerDelegate == null) { | 1335 | if (routerDelegate == null) { |
1321 | return routerDelegate = GetDelegate( | 1336 | return routerDelegate = GetDelegate( |
@@ -1324,6 +1339,8 @@ extension NavTwoExt on GetInterface { | @@ -1324,6 +1339,8 @@ extension NavTwoExt on GetInterface { | ||
1324 | transitionDelegate: transitionDelegate, | 1339 | transitionDelegate: transitionDelegate, |
1325 | backButtonPopMode: backButtonPopMode, | 1340 | backButtonPopMode: backButtonPopMode, |
1326 | preventDuplicateHandlingMode: preventDuplicateHandlingMode, | 1341 | preventDuplicateHandlingMode: preventDuplicateHandlingMode, |
1342 | + pages: pages, | ||
1343 | + navigatorKey: navigatorKey, | ||
1327 | ); | 1344 | ); |
1328 | } else { | 1345 | } else { |
1329 | return routerDelegate as GetDelegate; | 1346 | return routerDelegate as GetDelegate; |
1 | -import 'package:flutter/widgets.dart'; | ||
2 | - | ||
3 | -import '../../../get.dart'; | ||
4 | - | ||
5 | -// class GetRouterState extends GetxController { | ||
6 | -// GetRouterState({required this.currentTreeBranch}); | ||
7 | -// final List<GetPage> currentTreeBranch; | ||
8 | -// GetPage? get currentPage => currentTreeBranch.last; | ||
9 | - | ||
10 | -// static GetNavConfig? fromRoute(String route) { | ||
11 | -// final res = Get.routeTree.matchRoute(route); | ||
12 | -// if (res.treeBranch.isEmpty) return null; | ||
13 | -// return GetNavConfig( | ||
14 | -// currentTreeBranch: res.treeBranch, | ||
15 | -// location: route, | ||
16 | -// state: null, | ||
17 | -// ); | ||
18 | -// } | ||
19 | -// } | ||
20 | - | ||
21 | -/// This config enables us to navigate directly to a sub-url | ||
22 | -class GetNavConfig extends RouteInformation { | ||
23 | - final List<GetPage> currentTreeBranch; | ||
24 | - GetPage? get currentPage => currentTreeBranch.last; | ||
25 | - | ||
26 | - GetNavConfig({ | ||
27 | - required this.currentTreeBranch, | ||
28 | - required String? location, | ||
29 | - required Object? state, | ||
30 | - }) : super( | ||
31 | - location: location, | ||
32 | - state: state, | ||
33 | - ); | ||
34 | - | ||
35 | - GetNavConfig copyWith({ | ||
36 | - List<GetPage>? currentTreeBranch, | ||
37 | - required String? location, | ||
38 | - required Object? state, | ||
39 | - }) { | ||
40 | - return GetNavConfig( | ||
41 | - currentTreeBranch: currentTreeBranch ?? this.currentTreeBranch, | ||
42 | - location: location ?? this.location, | ||
43 | - state: state ?? this.state, | ||
44 | - ); | ||
45 | - } | ||
46 | - | ||
47 | - static GetNavConfig? fromRoute(String route) { | ||
48 | - final res = Get.routeTree.matchRoute(route); | ||
49 | - if (res.treeBranch.isEmpty) return null; | ||
50 | - return GetNavConfig( | ||
51 | - currentTreeBranch: res.treeBranch, | ||
52 | - location: route, | ||
53 | - state: null, | ||
54 | - ); | ||
55 | - } | ||
56 | - | ||
57 | - @override | ||
58 | - String toString() => ''' | ||
59 | -======GetNavConfig=====\ncurrentTreeBranch: $currentTreeBranch\ncurrentPage: $currentPage\n======GetNavConfig====='''; | ||
60 | -} |
1 | -import 'dart:async'; | ||
2 | - | ||
3 | -import 'package:flutter/foundation.dart'; | ||
4 | -import 'package:flutter/material.dart'; | ||
5 | - | ||
6 | -import '../../../get.dart'; | ||
7 | -import '../../../get_state_manager/src/simple/list_notifier.dart'; | ||
8 | - | ||
9 | -class GetDelegate extends RouterDelegate<GetNavConfig> | ||
10 | - with ListenableMixin, ListNotifierMixin { | ||
11 | - final List<GetNavConfig> history = <GetNavConfig>[]; | ||
12 | - final PopMode backButtonPopMode; | ||
13 | - final PreventDuplicateHandlingMode preventDuplicateHandlingMode; | ||
14 | - | ||
15 | - final GetPage notFoundRoute; | ||
16 | - | ||
17 | - final List<NavigatorObserver>? navigatorObservers; | ||
18 | - final TransitionDelegate<dynamic>? transitionDelegate; | ||
19 | - | ||
20 | - final _allCompleters = <GetPage, Completer>{}; | ||
21 | - | ||
22 | - GetDelegate({ | ||
23 | - GetPage? notFoundRoute, | ||
24 | - this.navigatorObservers, | ||
25 | - this.transitionDelegate, | ||
26 | - this.backButtonPopMode = PopMode.History, | ||
27 | - this.preventDuplicateHandlingMode = | ||
28 | - PreventDuplicateHandlingMode.ReorderRoutes, | ||
29 | - }) : notFoundRoute = notFoundRoute ?? | ||
30 | - GetPage( | ||
31 | - name: '/404', | ||
32 | - page: () => Scaffold( | ||
33 | - body: Text('Route not found'), | ||
34 | - ), | ||
35 | - ) { | ||
36 | - Get.log('GetDelegate is created !'); | ||
37 | - } | ||
38 | - | ||
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()); | ||
103 | - } | ||
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(); | ||
122 | - } | ||
123 | - } | ||
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 | ||
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; | ||
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; | ||
216 | - } | ||
217 | - | ||
218 | - @override | ||
219 | - Future<void> setNewRoutePath(GetNavConfig configuration) async { | ||
220 | - await pushHistory(configuration); | ||
221 | - } | ||
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(); | ||
231 | - } | ||
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 | - } | ||
254 | - } | ||
255 | - | ||
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 | - } | ||
264 | - } | ||
265 | - | ||
266 | - bool _canPopHistory() { | ||
267 | - return history.length > 1; | ||
268 | - } | ||
269 | - | ||
270 | - bool _canPopPage() { | ||
271 | - final currentTreeBranch = currentConfiguration?.currentTreeBranch; | ||
272 | - if (currentTreeBranch == null) return false; | ||
273 | - return currentTreeBranch.length > 1 ? true : _canPopHistory(); | ||
274 | - } | ||
275 | - | ||
276 | - Future<GetNavConfig?> _doPopHistory() async { | ||
277 | - return await _unsafeHistoryRemoveAt(history.length - 1); | ||
278 | - } | ||
279 | - | ||
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(); | ||
320 | - } | ||
321 | - } | ||
322 | - | ||
323 | - bool _onPopVisualRoute(Route<dynamic> route, dynamic result) { | ||
324 | - final didPop = route.didPop(result); | ||
325 | - if (!didPop) { | ||
326 | - return false; | ||
327 | - } | ||
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); | ||
336 | - } | ||
337 | - if (_allCompleters.containsKey(settings)) { | ||
338 | - _allCompleters[settings]?.complete(route.popped); | ||
339 | - } | ||
340 | - } | ||
341 | - refresh(); | ||
342 | - | ||
343 | - return true; | ||
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 | - } | ||
415 | -} | ||
416 | - | ||
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) { | ||
430 | - final didPop = route.didPop(result); | ||
431 | - if (!didPop) { | ||
432 | - return false; | ||
433 | - } | ||
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>(), | ||
444 | - ); | ||
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 | -} |
@@ -7,7 +7,6 @@ import '../../../get_instance/get_instance.dart'; | @@ -7,7 +7,6 @@ import '../../../get_instance/get_instance.dart'; | ||
7 | import '../../../get_state_manager/get_state_manager.dart'; | 7 | import '../../../get_state_manager/get_state_manager.dart'; |
8 | import '../../../get_utils/get_utils.dart'; | 8 | import '../../../get_utils/get_utils.dart'; |
9 | import '../../get_navigation.dart'; | 9 | import '../../get_navigation.dart'; |
10 | -import 'root_controller.dart'; | ||
11 | 10 | ||
12 | class GetCupertinoApp extends StatelessWidget { | 11 | class GetCupertinoApp extends StatelessWidget { |
13 | final GlobalKey<NavigatorState>? navigatorKey; | 12 | final GlobalKey<NavigatorState>? navigatorKey; |
@@ -52,7 +51,7 @@ class GetCupertinoApp extends StatelessWidget { | @@ -52,7 +51,7 @@ class GetCupertinoApp extends StatelessWidget { | ||
52 | final LogWriterCallback? logWriterCallback; | 51 | final LogWriterCallback? logWriterCallback; |
53 | final bool? popGesture; | 52 | final bool? popGesture; |
54 | final SmartManagement smartManagement; | 53 | final SmartManagement smartManagement; |
55 | - final Bindings? initialBinding; | 54 | + final BindingsInterface? initialBinding; |
56 | final Duration? transitionDuration; | 55 | final Duration? transitionDuration; |
57 | final bool? defaultGlobalState; | 56 | final bool? defaultGlobalState; |
58 | final List<GetPage>? getPages; | 57 | final List<GetPage>? getPages; |
@@ -63,7 +62,7 @@ class GetCupertinoApp extends StatelessWidget { | @@ -63,7 +62,7 @@ class GetCupertinoApp extends StatelessWidget { | ||
63 | final BackButtonDispatcher? backButtonDispatcher; | 62 | final BackButtonDispatcher? backButtonDispatcher; |
64 | final CupertinoThemeData? theme; | 63 | final CupertinoThemeData? theme; |
65 | final bool useInheritedMediaQuery; | 64 | final bool useInheritedMediaQuery; |
66 | - const GetCupertinoApp({ | 65 | + GetCupertinoApp({ |
67 | Key? key, | 66 | Key? key, |
68 | this.theme, | 67 | this.theme, |
69 | this.navigatorKey, | 68 | this.navigatorKey, |
@@ -116,17 +115,28 @@ class GetCupertinoApp extends StatelessWidget { | @@ -116,17 +115,28 @@ class GetCupertinoApp extends StatelessWidget { | ||
116 | this.highContrastDarkTheme, | 115 | this.highContrastDarkTheme, |
117 | this.actions, | 116 | this.actions, |
118 | }) : routeInformationProvider = null, | 117 | }) : routeInformationProvider = null, |
118 | + backButtonDispatcher = null, | ||
119 | routeInformationParser = null, | 119 | routeInformationParser = null, |
120 | routerDelegate = null, | 120 | routerDelegate = null, |
121 | - backButtonDispatcher = null, | ||
122 | super(key: key); | 121 | super(key: key); |
123 | 122 | ||
123 | + static String _cleanRouteName(String name) { | ||
124 | + name = name.replaceAll('() => ', ''); | ||
125 | + | ||
126 | + /// uncommonent for URL styling. | ||
127 | + // name = name.paramCase!; | ||
128 | + if (!name.startsWith('/')) { | ||
129 | + name = '/$name'; | ||
130 | + } | ||
131 | + return Uri.tryParse(name)?.toString() ?? name; | ||
132 | + } | ||
133 | + | ||
124 | GetCupertinoApp.router({ | 134 | GetCupertinoApp.router({ |
125 | Key? key, | 135 | Key? key, |
126 | this.theme, | 136 | this.theme, |
127 | this.routeInformationProvider, | 137 | this.routeInformationProvider, |
128 | - RouteInformationParser<Object>? routeInformationParser, | ||
129 | - RouterDelegate<Object>? routerDelegate, | 138 | + this.routeInformationParser, |
139 | + this.routerDelegate, | ||
130 | this.backButtonDispatcher, | 140 | this.backButtonDispatcher, |
131 | this.builder, | 141 | this.builder, |
132 | this.title = '', | 142 | this.title = '', |
@@ -166,35 +176,30 @@ class GetCupertinoApp extends StatelessWidget { | @@ -166,35 +176,30 @@ class GetCupertinoApp extends StatelessWidget { | ||
166 | this.transitionDuration, | 176 | this.transitionDuration, |
167 | this.defaultGlobalState, | 177 | this.defaultGlobalState, |
168 | this.getPages, | 178 | this.getPages, |
179 | + this.navigatorObservers, | ||
169 | this.unknownRoute, | 180 | this.unknownRoute, |
170 | - }) : routerDelegate = routerDelegate ??= Get.createDelegate( | ||
171 | - notFoundRoute: unknownRoute, | ||
172 | - ), | ||
173 | - routeInformationParser = | ||
174 | - routeInformationParser ??= Get.createInformationParser( | ||
175 | - initialRoute: getPages?.first.name ?? '/', | ||
176 | - ), | ||
177 | - navigatorObservers = null, | ||
178 | - navigatorKey = null, | 181 | + }) : navigatorKey = null, |
179 | onGenerateRoute = null, | 182 | onGenerateRoute = null, |
180 | home = null, | 183 | home = null, |
181 | onGenerateInitialRoutes = null, | 184 | onGenerateInitialRoutes = null, |
182 | onUnknownRoute = null, | 185 | onUnknownRoute = null, |
183 | routes = null, | 186 | routes = null, |
184 | initialRoute = null, | 187 | initialRoute = null, |
185 | - super(key: key) { | ||
186 | - Get.routerDelegate = routerDelegate; | ||
187 | - Get.routeInformationParser = routeInformationParser; | ||
188 | - } | 188 | + super(key: key); |
189 | 189 | ||
190 | @override | 190 | @override |
191 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 191 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
192 | init: Get.rootController, | 192 | init: Get.rootController, |
193 | dispose: (d) { | 193 | dispose: (d) { |
194 | onDispose?.call(); | 194 | onDispose?.call(); |
195 | + Get.clearRouteTree(); | ||
196 | + Get.clearTranslations(); | ||
197 | + Get.resetRootNavigator(); | ||
198 | + Get.routerDelegate = null; | ||
199 | + Get.routeInformationParser = null; | ||
195 | }, | 200 | }, |
196 | initState: (i) { | 201 | initState: (i) { |
197 | - Get.engine!.addPostFrameCallback((timeStamp) { | 202 | + Get.engine.addPostFrameCallback((timeStamp) { |
198 | onReady?.call(); | 203 | onReady?.call(); |
199 | }); | 204 | }); |
200 | if (locale != null) Get.locale = locale; | 205 | if (locale != null) Get.locale = locale; |
@@ -212,6 +217,13 @@ class GetCupertinoApp extends StatelessWidget { | @@ -212,6 +217,13 @@ class GetCupertinoApp extends StatelessWidget { | ||
212 | initialBinding?.dependencies(); | 217 | initialBinding?.dependencies(); |
213 | if (getPages != null) { | 218 | if (getPages != null) { |
214 | Get.addPages(getPages!); | 219 | Get.addPages(getPages!); |
220 | + } else { | ||
221 | + Get.addPage( | ||
222 | + GetPage( | ||
223 | + name: _cleanRouteName("/${home.runtimeType}"), | ||
224 | + page: () => home!, | ||
225 | + ), | ||
226 | + ); | ||
215 | } | 227 | } |
216 | 228 | ||
217 | Get.smartManagement = smartManagement; | 229 | Get.smartManagement = smartManagement; |
@@ -227,46 +239,11 @@ class GetCupertinoApp extends StatelessWidget { | @@ -227,46 +239,11 @@ class GetCupertinoApp extends StatelessWidget { | ||
227 | transitionDuration ?? Get.defaultTransitionDuration, | 239 | transitionDuration ?? Get.defaultTransitionDuration, |
228 | ); | 240 | ); |
229 | }, | 241 | }, |
230 | - builder: (_) => routerDelegate != null | ||
231 | - ? CupertinoApp.router( | ||
232 | - routerDelegate: routerDelegate!, | ||
233 | - routeInformationParser: routeInformationParser!, | ||
234 | - backButtonDispatcher: backButtonDispatcher, | ||
235 | - routeInformationProvider: routeInformationProvider, | ||
236 | - key: _.unikey, | ||
237 | - theme: theme, | ||
238 | - builder: defaultBuilder, | ||
239 | - title: title, | ||
240 | - onGenerateTitle: onGenerateTitle, | ||
241 | - color: color, | ||
242 | - locale: Get.locale ?? locale, | ||
243 | - localizationsDelegates: localizationsDelegates, | ||
244 | - localeListResolutionCallback: localeListResolutionCallback, | ||
245 | - localeResolutionCallback: localeResolutionCallback, | ||
246 | - supportedLocales: supportedLocales, | ||
247 | - showPerformanceOverlay: showPerformanceOverlay, | ||
248 | - checkerboardRasterCacheImages: checkerboardRasterCacheImages, | ||
249 | - checkerboardOffscreenLayers: checkerboardOffscreenLayers, | ||
250 | - showSemanticsDebugger: showSemanticsDebugger, | ||
251 | - debugShowCheckedModeBanner: debugShowCheckedModeBanner, | ||
252 | - shortcuts: shortcuts, | ||
253 | - useInheritedMediaQuery: useInheritedMediaQuery, | ||
254 | - ) | ||
255 | - : CupertinoApp( | ||
256 | - key: _.unikey, | ||
257 | - theme: theme, | ||
258 | - navigatorKey: (navigatorKey == null | ||
259 | - ? Get.key | ||
260 | - : Get.addKey(navigatorKey!)), | ||
261 | - home: home, | ||
262 | - routes: routes ?? const <String, WidgetBuilder>{}, | ||
263 | - initialRoute: initialRoute, | ||
264 | - onGenerateRoute: | ||
265 | - (getPages != null ? generator : onGenerateRoute), | ||
266 | - onGenerateInitialRoutes: (getPages == null || home != null) | ||
267 | - ? onGenerateInitialRoutes | ||
268 | - : initialRoutesGenerate, | ||
269 | - onUnknownRoute: onUnknownRoute, | 242 | + builder: (_) { |
243 | + final routerDelegate = Get.createDelegate( | ||
244 | + pages: getPages ?? [], | ||
245 | + notFoundRoute: unknownRoute, | ||
246 | + navigatorKey: navigatorKey, | ||
270 | navigatorObservers: (navigatorObservers == null | 247 | navigatorObservers: (navigatorObservers == null |
271 | ? <NavigatorObserver>[ | 248 | ? <NavigatorObserver>[ |
272 | GetObserver(routingCallback, Get.routing) | 249 | GetObserver(routingCallback, Get.routing) |
@@ -274,7 +251,20 @@ class GetCupertinoApp extends StatelessWidget { | @@ -274,7 +251,20 @@ class GetCupertinoApp extends StatelessWidget { | ||
274 | : <NavigatorObserver>[ | 251 | : <NavigatorObserver>[ |
275 | GetObserver(routingCallback, Get.routing) | 252 | GetObserver(routingCallback, Get.routing) |
276 | ] | 253 | ] |
277 | - ..addAll(navigatorObservers!)), | 254 | + ..addAll(navigatorObservers!))); |
255 | + final routeInformationParser = Get.createInformationParser( | ||
256 | + initialRoute: initialRoute ?? | ||
257 | + getPages?.first.name ?? | ||
258 | + _cleanRouteName("/${home.runtimeType}"), | ||
259 | + ); | ||
260 | + | ||
261 | + return CupertinoApp.router( | ||
262 | + routerDelegate: routerDelegate, | ||
263 | + routeInformationParser: routeInformationParser, | ||
264 | + backButtonDispatcher: backButtonDispatcher, | ||
265 | + routeInformationProvider: routeInformationProvider, | ||
266 | + key: _.unikey, | ||
267 | + theme: theme, | ||
278 | builder: defaultBuilder, | 268 | builder: defaultBuilder, |
279 | title: title, | 269 | title: title, |
280 | onGenerateTitle: onGenerateTitle, | 270 | onGenerateTitle: onGenerateTitle, |
@@ -291,8 +281,8 @@ class GetCupertinoApp extends StatelessWidget { | @@ -291,8 +281,8 @@ class GetCupertinoApp extends StatelessWidget { | ||
291 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, | 281 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, |
292 | shortcuts: shortcuts, | 282 | shortcuts: shortcuts, |
293 | useInheritedMediaQuery: useInheritedMediaQuery, | 283 | useInheritedMediaQuery: useInheritedMediaQuery, |
294 | - // actions: actions, | ||
295 | - ), | 284 | + ); |
285 | + }, | ||
296 | ); | 286 | ); |
297 | 287 | ||
298 | Widget defaultBuilder(BuildContext context, Widget? child) { | 288 | Widget defaultBuilder(BuildContext context, Widget? child) { |
1 | -import 'package:flutter/cupertino.dart'; | ||
2 | import 'package:flutter/foundation.dart'; | 1 | import 'package:flutter/foundation.dart'; |
3 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
4 | 3 | ||
@@ -7,7 +6,6 @@ import '../../../get_instance/get_instance.dart'; | @@ -7,7 +6,6 @@ import '../../../get_instance/get_instance.dart'; | ||
7 | import '../../../get_state_manager/get_state_manager.dart'; | 6 | import '../../../get_state_manager/get_state_manager.dart'; |
8 | import '../../../get_utils/get_utils.dart'; | 7 | import '../../../get_utils/get_utils.dart'; |
9 | import '../../get_navigation.dart'; | 8 | import '../../get_navigation.dart'; |
10 | -import 'root_controller.dart'; | ||
11 | 9 | ||
12 | class GetMaterialApp extends StatelessWidget { | 10 | class GetMaterialApp extends StatelessWidget { |
13 | final GlobalKey<NavigatorState>? navigatorKey; | 11 | final GlobalKey<NavigatorState>? navigatorKey; |
@@ -58,7 +56,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -58,7 +56,7 @@ class GetMaterialApp extends StatelessWidget { | ||
58 | final LogWriterCallback? logWriterCallback; | 56 | final LogWriterCallback? logWriterCallback; |
59 | final bool? popGesture; | 57 | final bool? popGesture; |
60 | final SmartManagement smartManagement; | 58 | final SmartManagement smartManagement; |
61 | - final Bindings? initialBinding; | 59 | + final BindingsInterface? initialBinding; |
62 | final Duration? transitionDuration; | 60 | final Duration? transitionDuration; |
63 | final bool? defaultGlobalState; | 61 | final bool? defaultGlobalState; |
64 | final List<GetPage>? getPages; | 62 | final List<GetPage>? getPages; |
@@ -68,7 +66,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -68,7 +66,7 @@ class GetMaterialApp extends StatelessWidget { | ||
68 | final RouterDelegate<Object>? routerDelegate; | 66 | final RouterDelegate<Object>? routerDelegate; |
69 | final BackButtonDispatcher? backButtonDispatcher; | 67 | final BackButtonDispatcher? backButtonDispatcher; |
70 | final bool useInheritedMediaQuery; | 68 | final bool useInheritedMediaQuery; |
71 | - const GetMaterialApp({ | 69 | + GetMaterialApp({ |
72 | Key? key, | 70 | Key? key, |
73 | this.navigatorKey, | 71 | this.navigatorKey, |
74 | this.scaffoldMessengerKey, | 72 | this.scaffoldMessengerKey, |
@@ -126,17 +124,28 @@ class GetMaterialApp extends StatelessWidget { | @@ -126,17 +124,28 @@ class GetMaterialApp extends StatelessWidget { | ||
126 | this.highContrastDarkTheme, | 124 | this.highContrastDarkTheme, |
127 | this.actions, | 125 | this.actions, |
128 | }) : routeInformationProvider = null, | 126 | }) : routeInformationProvider = null, |
127 | + backButtonDispatcher = null, | ||
129 | routeInformationParser = null, | 128 | routeInformationParser = null, |
130 | routerDelegate = null, | 129 | routerDelegate = null, |
131 | - backButtonDispatcher = null, | ||
132 | super(key: key); | 130 | super(key: key); |
133 | 131 | ||
132 | + static String _cleanRouteName(String name) { | ||
133 | + name = name.replaceAll('() => ', ''); | ||
134 | + | ||
135 | + /// uncommonent for URL styling. | ||
136 | + // name = name.paramCase!; | ||
137 | + if (!name.startsWith('/')) { | ||
138 | + name = '/$name'; | ||
139 | + } | ||
140 | + return Uri.tryParse(name)?.toString() ?? name; | ||
141 | + } | ||
142 | + | ||
134 | GetMaterialApp.router({ | 143 | GetMaterialApp.router({ |
135 | Key? key, | 144 | Key? key, |
136 | this.routeInformationProvider, | 145 | this.routeInformationProvider, |
137 | this.scaffoldMessengerKey, | 146 | this.scaffoldMessengerKey, |
138 | - RouteInformationParser<Object>? routeInformationParser, | ||
139 | - RouterDelegate<Object>? routerDelegate, | 147 | + this.routeInformationParser, |
148 | + this.routerDelegate, | ||
140 | this.backButtonDispatcher, | 149 | this.backButtonDispatcher, |
141 | this.builder, | 150 | this.builder, |
142 | this.title = '', | 151 | this.title = '', |
@@ -183,34 +192,30 @@ class GetMaterialApp extends StatelessWidget { | @@ -183,34 +192,30 @@ class GetMaterialApp extends StatelessWidget { | ||
183 | this.getPages, | 192 | this.getPages, |
184 | this.navigatorObservers, | 193 | this.navigatorObservers, |
185 | this.unknownRoute, | 194 | this.unknownRoute, |
186 | - }) : routerDelegate = routerDelegate ??= Get.createDelegate( | ||
187 | - notFoundRoute: unknownRoute, | ||
188 | - ), | ||
189 | - routeInformationParser = | ||
190 | - routeInformationParser ??= Get.createInformationParser( | ||
191 | - initialRoute: getPages?.first.name ?? '/', | ||
192 | - ), | ||
193 | - //navigatorObservers = null, | ||
194 | - navigatorKey = null, | 195 | + }) : navigatorKey = null, |
195 | onGenerateRoute = null, | 196 | onGenerateRoute = null, |
196 | home = null, | 197 | home = null, |
197 | onGenerateInitialRoutes = null, | 198 | onGenerateInitialRoutes = null, |
198 | onUnknownRoute = null, | 199 | onUnknownRoute = null, |
199 | routes = null, | 200 | routes = null, |
200 | initialRoute = null, | 201 | initialRoute = null, |
201 | - super(key: key) { | ||
202 | - Get.routerDelegate = routerDelegate; | ||
203 | - Get.routeInformationParser = routeInformationParser; | ||
204 | - } | 202 | + super(key: key); |
205 | 203 | ||
206 | @override | 204 | @override |
207 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 205 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
208 | init: Get.rootController, | 206 | init: Get.rootController, |
209 | dispose: (d) { | 207 | dispose: (d) { |
210 | onDispose?.call(); | 208 | onDispose?.call(); |
209 | + Get.clearRouteTree(); | ||
210 | + Get.clearTranslations(); | ||
211 | + Get.resetRootNavigator(); | ||
212 | + Get.routerDelegate = null; | ||
213 | + Get.routeInformationParser = null; | ||
211 | }, | 214 | }, |
212 | initState: (i) { | 215 | initState: (i) { |
213 | - Get.engine!.addPostFrameCallback((timeStamp) { | 216 | + // Get.routerDelegate = routerDelegate; |
217 | + // Get.routeInformationParser = routeInformationParser; | ||
218 | + Get.engine.addPostFrameCallback((timeStamp) { | ||
214 | onReady?.call(); | 219 | onReady?.call(); |
215 | }); | 220 | }); |
216 | if (locale != null) Get.locale = locale; | 221 | if (locale != null) Get.locale = locale; |
@@ -228,6 +233,13 @@ class GetMaterialApp extends StatelessWidget { | @@ -228,6 +233,13 @@ class GetMaterialApp extends StatelessWidget { | ||
228 | initialBinding?.dependencies(); | 233 | initialBinding?.dependencies(); |
229 | if (getPages != null) { | 234 | if (getPages != null) { |
230 | Get.addPages(getPages!); | 235 | Get.addPages(getPages!); |
236 | + } else { | ||
237 | + Get.addPage( | ||
238 | + GetPage( | ||
239 | + name: _cleanRouteName("/${home.runtimeType}"), | ||
240 | + page: () => home!, | ||
241 | + ), | ||
242 | + ); | ||
231 | } | 243 | } |
232 | 244 | ||
233 | //Get.setDefaultDelegate(routerDelegate); | 245 | //Get.setDefaultDelegate(routerDelegate); |
@@ -244,10 +256,26 @@ class GetMaterialApp extends StatelessWidget { | @@ -244,10 +256,26 @@ class GetMaterialApp extends StatelessWidget { | ||
244 | transitionDuration ?? Get.defaultTransitionDuration, | 256 | transitionDuration ?? Get.defaultTransitionDuration, |
245 | ); | 257 | ); |
246 | }, | 258 | }, |
247 | - builder: (_) => routerDelegate != null | ||
248 | - ? MaterialApp.router( | ||
249 | - routerDelegate: routerDelegate!, | ||
250 | - routeInformationParser: routeInformationParser!, | 259 | + builder: (_) { |
260 | + final routerDelegate = Get.createDelegate( | ||
261 | + pages: getPages ?? [], | ||
262 | + notFoundRoute: unknownRoute, | ||
263 | + navigatorKey: navigatorKey, | ||
264 | + navigatorObservers: (navigatorObservers == null | ||
265 | + ? <NavigatorObserver>[GetObserver(routingCallback, Get.routing)] | ||
266 | + : <NavigatorObserver>[ | ||
267 | + GetObserver(routingCallback, Get.routing), | ||
268 | + ...navigatorObservers! | ||
269 | + ])); | ||
270 | + | ||
271 | + final routeInformationParser = Get.createInformationParser( | ||
272 | + initialRoute: initialRoute ?? | ||
273 | + getPages?.first.name ?? | ||
274 | + _cleanRouteName("/${home.runtimeType}"), | ||
275 | + ); | ||
276 | + return MaterialApp.router( | ||
277 | + routerDelegate: routerDelegate, | ||
278 | + routeInformationParser: routeInformationParser, | ||
251 | backButtonDispatcher: backButtonDispatcher, | 279 | backButtonDispatcher: backButtonDispatcher, |
252 | routeInformationProvider: routeInformationProvider, | 280 | routeInformationProvider: routeInformationProvider, |
253 | key: _.unikey, | 281 | key: _.unikey, |
@@ -256,59 +284,10 @@ class GetMaterialApp extends StatelessWidget { | @@ -256,59 +284,10 @@ class GetMaterialApp extends StatelessWidget { | ||
256 | onGenerateTitle: onGenerateTitle, | 284 | onGenerateTitle: onGenerateTitle, |
257 | color: color, | 285 | color: color, |
258 | theme: _.theme ?? theme ?? ThemeData.fallback(), | 286 | theme: _.theme ?? theme ?? ThemeData.fallback(), |
259 | - darkTheme: | ||
260 | - _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), | ||
261 | - themeMode: _.themeMode ?? themeMode, | ||
262 | - locale: Get.locale ?? locale, | ||
263 | - scaffoldMessengerKey: | ||
264 | - scaffoldMessengerKey ?? _.scaffoldMessengerKey, | ||
265 | - localizationsDelegates: localizationsDelegates, | ||
266 | - localeListResolutionCallback: localeListResolutionCallback, | ||
267 | - localeResolutionCallback: localeResolutionCallback, | ||
268 | - supportedLocales: supportedLocales, | ||
269 | - debugShowMaterialGrid: debugShowMaterialGrid, | ||
270 | - showPerformanceOverlay: showPerformanceOverlay, | ||
271 | - checkerboardRasterCacheImages: checkerboardRasterCacheImages, | ||
272 | - checkerboardOffscreenLayers: checkerboardOffscreenLayers, | ||
273 | - showSemanticsDebugger: showSemanticsDebugger, | ||
274 | - debugShowCheckedModeBanner: debugShowCheckedModeBanner, | ||
275 | - shortcuts: shortcuts, | ||
276 | - scrollBehavior: scrollBehavior, | ||
277 | - useInheritedMediaQuery: useInheritedMediaQuery, | ||
278 | - ) | ||
279 | - : MaterialApp( | ||
280 | - key: _.unikey, | ||
281 | - navigatorKey: (navigatorKey == null | ||
282 | - ? Get.key | ||
283 | - : Get.addKey(navigatorKey!)), | ||
284 | - scaffoldMessengerKey: | ||
285 | - scaffoldMessengerKey ?? _.scaffoldMessengerKey, | ||
286 | - home: home, | ||
287 | - routes: routes ?? const <String, WidgetBuilder>{}, | ||
288 | - initialRoute: initialRoute, | ||
289 | - onGenerateRoute: | ||
290 | - (getPages != null ? generator : onGenerateRoute), | ||
291 | - onGenerateInitialRoutes: (getPages == null || home != null) | ||
292 | - ? onGenerateInitialRoutes | ||
293 | - : initialRoutesGenerate, | ||
294 | - onUnknownRoute: onUnknownRoute, | ||
295 | - navigatorObservers: (navigatorObservers == null | ||
296 | - ? <NavigatorObserver>[ | ||
297 | - GetObserver(routingCallback, Get.routing) | ||
298 | - ] | ||
299 | - : <NavigatorObserver>[ | ||
300 | - GetObserver(routingCallback, Get.routing) | ||
301 | - ] | ||
302 | - ..addAll(navigatorObservers!)), | ||
303 | - builder: defaultBuilder, | ||
304 | - title: title, | ||
305 | - onGenerateTitle: onGenerateTitle, | ||
306 | - color: color, | ||
307 | - theme: _.theme ?? theme ?? ThemeData.fallback(), | ||
308 | - darkTheme: | ||
309 | - _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), | 287 | + darkTheme: _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), |
310 | themeMode: _.themeMode ?? themeMode, | 288 | themeMode: _.themeMode ?? themeMode, |
311 | locale: Get.locale ?? locale, | 289 | locale: Get.locale ?? locale, |
290 | + scaffoldMessengerKey: scaffoldMessengerKey ?? _.scaffoldMessengerKey, | ||
312 | localizationsDelegates: localizationsDelegates, | 291 | localizationsDelegates: localizationsDelegates, |
313 | localeListResolutionCallback: localeListResolutionCallback, | 292 | localeListResolutionCallback: localeListResolutionCallback, |
314 | localeResolutionCallback: localeResolutionCallback, | 293 | localeResolutionCallback: localeResolutionCallback, |
@@ -322,9 +301,8 @@ class GetMaterialApp extends StatelessWidget { | @@ -322,9 +301,8 @@ class GetMaterialApp extends StatelessWidget { | ||
322 | shortcuts: shortcuts, | 301 | shortcuts: shortcuts, |
323 | scrollBehavior: scrollBehavior, | 302 | scrollBehavior: scrollBehavior, |
324 | useInheritedMediaQuery: useInheritedMediaQuery, | 303 | useInheritedMediaQuery: useInheritedMediaQuery, |
325 | - // actions: actions, | ||
326 | - ), | ||
327 | ); | 304 | ); |
305 | + }); | ||
328 | 306 | ||
329 | Widget defaultBuilder(BuildContext context, Widget? child) { | 307 | Widget defaultBuilder(BuildContext context, Widget? child) { |
330 | return Directionality( | 308 | return Directionality( |
@@ -342,12 +320,12 @@ class GetMaterialApp extends StatelessWidget { | @@ -342,12 +320,12 @@ class GetMaterialApp extends StatelessWidget { | ||
342 | return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); | 320 | return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); |
343 | } | 321 | } |
344 | 322 | ||
345 | - List<Route<dynamic>> initialRoutesGenerate(String name) { | ||
346 | - return [ | ||
347 | - PageRedirect( | ||
348 | - settings: RouteSettings(name: name), | ||
349 | - unknownRoute: unknownRoute, | ||
350 | - ).page() | ||
351 | - ]; | ||
352 | - } | 323 | + // List<Route<dynamic>> initialRoutesGenerate(String name) { |
324 | + // return [ | ||
325 | + // PageRedirect( | ||
326 | + // settings: RouteSettings(name: name), | ||
327 | + // unknownRoute: unknownRoute, | ||
328 | + // ).page() | ||
329 | + // ]; | ||
330 | + // } | ||
353 | } | 331 | } |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | 2 | ||
3 | import '../../../get.dart'; | 3 | import '../../../get.dart'; |
4 | -import '../../../get_state_manager/get_state_manager.dart'; | ||
5 | -import '../../../get_utils/get_utils.dart'; | ||
6 | -import '../routes/custom_transition.dart'; | ||
7 | -import '../routes/observers/route_observer.dart'; | ||
8 | -import '../routes/transitions_type.dart'; | ||
9 | 4 | ||
10 | -class GetMaterialController extends SuperController { | 5 | +class GetMaterialController extends FullLifeCycleController { |
6 | + static GetMaterialController get to => Get.find(); | ||
7 | + | ||
11 | bool testMode = false; | 8 | bool testMode = false; |
12 | Key? unikey; | 9 | Key? unikey; |
13 | ThemeData? theme; | 10 | ThemeData? theme; |
@@ -33,14 +30,14 @@ class GetMaterialController extends SuperController { | @@ -33,14 +30,14 @@ class GetMaterialController extends SuperController { | ||
33 | 30 | ||
34 | CustomTransition? customTransition; | 31 | CustomTransition? customTransition; |
35 | 32 | ||
36 | - var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default'); | 33 | + Map<dynamic, GetDelegate> keys = {}; |
37 | 34 | ||
38 | - Map<dynamic, GlobalKey<NavigatorState>> keys = {}; | 35 | + GlobalKey<NavigatorState> get key => rootDelegate.navigatorKey; |
39 | 36 | ||
40 | - GlobalKey<NavigatorState> get key => _key; | 37 | + GetDelegate get rootDelegate => Get.createDelegate(); |
41 | 38 | ||
42 | GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { | 39 | GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { |
43 | - _key = newKey; | 40 | + rootDelegate.navigatorKey = newKey; |
44 | return key; | 41 | return key; |
45 | } | 42 | } |
46 | 43 | ||
@@ -54,18 +51,6 @@ class GetMaterialController extends SuperController { | @@ -54,18 +51,6 @@ class GetMaterialController extends SuperController { | ||
54 | }); | 51 | }); |
55 | } | 52 | } |
56 | 53 | ||
57 | - @override | ||
58 | - void onDetached() {} | ||
59 | - | ||
60 | - @override | ||
61 | - void onInactive() {} | ||
62 | - | ||
63 | - @override | ||
64 | - void onPaused() {} | ||
65 | - | ||
66 | - @override | ||
67 | - void onResumed() {} | ||
68 | - | ||
69 | void restartApp() { | 54 | void restartApp() { |
70 | unikey = UniqueKey(); | 55 | unikey = UniqueKey(); |
71 | update(); | 56 | update(); |
@@ -7,28 +7,30 @@ import '../../get.dart'; | @@ -7,28 +7,30 @@ import '../../get.dart'; | ||
7 | class RouterReportManager<T> { | 7 | class RouterReportManager<T> { |
8 | /// Holds a reference to `Get.reference` when the Instance was | 8 | /// Holds a reference to `Get.reference` when the Instance was |
9 | /// created to manage the memory. | 9 | /// created to manage the memory. |
10 | - static final Map<Route?, List<String>> _routesKey = {}; | 10 | + final Map<T?, List<String>> _routesKey = {}; |
11 | 11 | ||
12 | /// Stores the onClose() references of instances created with `Get.create()` | 12 | /// Stores the onClose() references of instances created with `Get.create()` |
13 | /// using the `Get.reference`. | 13 | /// using the `Get.reference`. |
14 | /// Experimental feature to keep the lifecycle and memory management with | 14 | /// Experimental feature to keep the lifecycle and memory management with |
15 | /// non-singleton instances. | 15 | /// non-singleton instances. |
16 | - static final Map<Route?, HashSet<Function>> _routesByCreate = {}; | 16 | + final Map<T?, HashSet<Function>> _routesByCreate = {}; |
17 | + | ||
18 | + static late final RouterReportManager instance = RouterReportManager(); | ||
17 | 19 | ||
18 | void printInstanceStack() { | 20 | void printInstanceStack() { |
19 | Get.log(_routesKey.toString()); | 21 | Get.log(_routesKey.toString()); |
20 | } | 22 | } |
21 | 23 | ||
22 | - static Route? _current; | 24 | + T? _current; |
23 | 25 | ||
24 | // ignore: use_setters_to_change_properties | 26 | // ignore: use_setters_to_change_properties |
25 | - static void reportCurrentRoute(Route newRoute) { | 27 | + void reportCurrentRoute(T newRoute) { |
26 | _current = newRoute; | 28 | _current = newRoute; |
27 | } | 29 | } |
28 | 30 | ||
29 | /// Links a Class instance [S] (or [tag]) to the current route. | 31 | /// Links a Class instance [S] (or [tag]) to the current route. |
30 | /// Requires usage of `GetMaterialApp`. | 32 | /// Requires usage of `GetMaterialApp`. |
31 | - static void reportDependencyLinkedToRoute(String depedencyKey) { | 33 | + void reportDependencyLinkedToRoute(String depedencyKey) { |
32 | if (_current == null) return; | 34 | if (_current == null) return; |
33 | if (_routesKey.containsKey(_current)) { | 35 | if (_routesKey.containsKey(_current)) { |
34 | _routesKey[_current!]!.add(depedencyKey); | 36 | _routesKey[_current!]!.add(depedencyKey); |
@@ -37,26 +39,26 @@ class RouterReportManager<T> { | @@ -37,26 +39,26 @@ class RouterReportManager<T> { | ||
37 | } | 39 | } |
38 | } | 40 | } |
39 | 41 | ||
40 | - static void clearRouteKeys() { | 42 | + void clearRouteKeys() { |
41 | _routesKey.clear(); | 43 | _routesKey.clear(); |
42 | _routesByCreate.clear(); | 44 | _routesByCreate.clear(); |
43 | } | 45 | } |
44 | 46 | ||
45 | - static void appendRouteByCreate(GetLifeCycleBase i) { | 47 | + void appendRouteByCreate(GetLifeCycleMixin i) { |
46 | _routesByCreate[_current] ??= HashSet<Function>(); | 48 | _routesByCreate[_current] ??= HashSet<Function>(); |
47 | // _routesByCreate[Get.reference]!.add(i.onDelete as Function); | 49 | // _routesByCreate[Get.reference]!.add(i.onDelete as Function); |
48 | _routesByCreate[_current]!.add(i.onDelete); | 50 | _routesByCreate[_current]!.add(i.onDelete); |
49 | } | 51 | } |
50 | 52 | ||
51 | - static void reportRouteDispose(Route disposed) { | 53 | + void reportRouteDispose(T disposed) { |
52 | if (Get.smartManagement != SmartManagement.onlyBuilder) { | 54 | if (Get.smartManagement != SmartManagement.onlyBuilder) { |
53 | - WidgetsBinding.instance!.addPostFrameCallback((_) { | 55 | + ambiguate(WidgetsBinding.instance)!.addPostFrameCallback((_) { |
54 | _removeDependencyByRoute(disposed); | 56 | _removeDependencyByRoute(disposed); |
55 | }); | 57 | }); |
56 | } | 58 | } |
57 | } | 59 | } |
58 | 60 | ||
59 | - static void reportRouteWillDispose(Route disposed) { | 61 | + void reportRouteWillDispose(T disposed) { |
60 | final keysToRemove = <String>[]; | 62 | final keysToRemove = <String>[]; |
61 | 63 | ||
62 | _routesKey[disposed]?.forEach(keysToRemove.add); | 64 | _routesKey[disposed]?.forEach(keysToRemove.add); |
@@ -85,7 +87,7 @@ class RouterReportManager<T> { | @@ -85,7 +87,7 @@ class RouterReportManager<T> { | ||
85 | /// using `Get.smartManagement` as [SmartManagement.full] or | 87 | /// using `Get.smartManagement` as [SmartManagement.full] or |
86 | /// [SmartManagement.keepFactory] | 88 | /// [SmartManagement.keepFactory] |
87 | /// Meant for internal usage of `GetPageRoute` and `GetDialogRoute` | 89 | /// Meant for internal usage of `GetPageRoute` and `GetDialogRoute` |
88 | - static void _removeDependencyByRoute(Route routeName) { | 90 | + void _removeDependencyByRoute(T routeName) { |
89 | final keysToRemove = <String>[]; | 91 | final keysToRemove = <String>[]; |
90 | 92 | ||
91 | _routesKey[routeName]?.forEach(keysToRemove.add); | 93 | _routesKey[routeName]?.forEach(keysToRemove.add); |
1 | +import 'dart:math' show sqrt, max; | ||
2 | +import 'dart:ui' show lerpDouble; | ||
3 | + | ||
4 | +import 'package:flutter/material.dart'; | ||
5 | + | ||
6 | +class CircularRevealClipper extends CustomClipper<Path> { | ||
7 | + final double fraction; | ||
8 | + final Alignment? centerAlignment; | ||
9 | + final Offset? centerOffset; | ||
10 | + final double? minRadius; | ||
11 | + final double? maxRadius; | ||
12 | + | ||
13 | + CircularRevealClipper({ | ||
14 | + required this.fraction, | ||
15 | + this.centerAlignment, | ||
16 | + this.centerOffset, | ||
17 | + this.minRadius, | ||
18 | + this.maxRadius, | ||
19 | + }); | ||
20 | + | ||
21 | + @override | ||
22 | + Path getClip(Size size) { | ||
23 | + final center = centerAlignment?.alongSize(size) ?? | ||
24 | + centerOffset ?? | ||
25 | + Offset(size.width / 2, size.height / 2); | ||
26 | + final minRadius = this.minRadius ?? 0; | ||
27 | + final maxRadius = this.maxRadius ?? calcMaxRadius(size, center); | ||
28 | + | ||
29 | + return Path() | ||
30 | + ..addOval( | ||
31 | + Rect.fromCircle( | ||
32 | + center: center, | ||
33 | + radius: lerpDouble(minRadius, maxRadius, fraction)!, | ||
34 | + ), | ||
35 | + ); | ||
36 | + } | ||
37 | + | ||
38 | + @override | ||
39 | + bool shouldReclip(CustomClipper<Path> oldClipper) => true; | ||
40 | + | ||
41 | + static double calcMaxRadius(Size size, Offset center) { | ||
42 | + final w = max(center.dx, size.width - center.dx); | ||
43 | + final h = max(center.dy, size.height - center.dy); | ||
44 | + return sqrt(w * w + h * h); | ||
45 | + } | ||
46 | +} |
@@ -2,22 +2,33 @@ import 'package:flutter/material.dart'; | @@ -2,22 +2,33 @@ import 'package:flutter/material.dart'; | ||
2 | 2 | ||
3 | import '../../../get.dart'; | 3 | import '../../../get.dart'; |
4 | import '../router_report.dart'; | 4 | import '../router_report.dart'; |
5 | -import 'custom_transition.dart'; | ||
6 | -import 'get_transition_mixin.dart'; | ||
7 | -import 'route_middleware.dart'; | ||
8 | -import 'transitions_type.dart'; | 5 | + |
6 | +@optionalTypeArgs | ||
7 | +mixin RouteReportMixin<T extends StatefulWidget> on State<T> { | ||
8 | + @override | ||
9 | + void initState() { | ||
10 | + super.initState(); | ||
11 | + RouterReportManager.instance.reportCurrentRoute(this); | ||
12 | + } | ||
13 | + | ||
14 | + @override | ||
15 | + void dispose() { | ||
16 | + super.dispose(); | ||
17 | + RouterReportManager.instance.reportRouteDispose(this); | ||
18 | + } | ||
19 | +} | ||
9 | 20 | ||
10 | mixin PageRouteReportMixin<T> on Route<T> { | 21 | mixin PageRouteReportMixin<T> on Route<T> { |
11 | @override | 22 | @override |
12 | void install() { | 23 | void install() { |
13 | super.install(); | 24 | super.install(); |
14 | - RouterReportManager.reportCurrentRoute(this); | 25 | + RouterReportManager.instance.reportCurrentRoute(this); |
15 | } | 26 | } |
16 | 27 | ||
17 | @override | 28 | @override |
18 | void dispose() { | 29 | void dispose() { |
19 | super.dispose(); | 30 | super.dispose(); |
20 | - RouterReportManager.reportRouteDispose(this); | 31 | + RouterReportManager.instance.reportRouteDispose(this); |
21 | } | 32 | } |
22 | } | 33 | } |
23 | 34 | ||
@@ -40,8 +51,8 @@ class GetPageRoute<T> extends PageRoute<T> | @@ -40,8 +51,8 @@ class GetPageRoute<T> extends PageRoute<T> | ||
40 | this.customTransition, | 51 | this.customTransition, |
41 | this.barrierDismissible = false, | 52 | this.barrierDismissible = false, |
42 | this.barrierColor, | 53 | this.barrierColor, |
43 | - this.binding, | ||
44 | - this.bindings, | 54 | + this.bindings = const [], |
55 | + this.binds, | ||
45 | this.routeName, | 56 | this.routeName, |
46 | this.page, | 57 | this.page, |
47 | this.title, | 58 | this.title, |
@@ -50,7 +61,11 @@ class GetPageRoute<T> extends PageRoute<T> | @@ -50,7 +61,11 @@ class GetPageRoute<T> extends PageRoute<T> | ||
50 | this.maintainState = true, | 61 | this.maintainState = true, |
51 | bool fullscreenDialog = false, | 62 | bool fullscreenDialog = false, |
52 | this.middlewares, | 63 | this.middlewares, |
53 | - }) : super(settings: settings, fullscreenDialog: fullscreenDialog); | 64 | + }) : super( |
65 | + settings: settings, | ||
66 | + fullscreenDialog: fullscreenDialog, | ||
67 | + // builder: (context) => Container(), | ||
68 | + ); | ||
54 | 69 | ||
55 | @override | 70 | @override |
56 | final Duration transitionDuration; | 71 | final Duration transitionDuration; |
@@ -58,9 +73,9 @@ class GetPageRoute<T> extends PageRoute<T> | @@ -58,9 +73,9 @@ class GetPageRoute<T> extends PageRoute<T> | ||
58 | final String? routeName; | 73 | final String? routeName; |
59 | //final String reference; | 74 | //final String reference; |
60 | final CustomTransition? customTransition; | 75 | final CustomTransition? customTransition; |
61 | - final Bindings? binding; | 76 | + final List<BindingsInterface> bindings; |
62 | final Map<String, String>? parameter; | 77 | final Map<String, String>? parameter; |
63 | - final List<Bindings>? bindings; | 78 | + final List<Bind>? binds; |
64 | 79 | ||
65 | @override | 80 | @override |
66 | final bool showCupertinoParallax; | 81 | final bool showCupertinoParallax; |
@@ -98,20 +113,33 @@ class GetPageRoute<T> extends PageRoute<T> | @@ -98,20 +113,33 @@ class GetPageRoute<T> extends PageRoute<T> | ||
98 | if (_child != null) return _child!; | 113 | if (_child != null) return _child!; |
99 | final middlewareRunner = MiddlewareRunner(middlewares); | 114 | final middlewareRunner = MiddlewareRunner(middlewares); |
100 | 115 | ||
101 | - final localbindings = [ | ||
102 | - if (bindings != null) ...bindings!, | ||
103 | - if (binding != null) ...[binding!] | ||
104 | - ]; | ||
105 | - final bindingsToBind = middlewareRunner.runOnBindingsStart(localbindings); | ||
106 | - if (bindingsToBind != null) { | ||
107 | - for (final binding in bindingsToBind) { | ||
108 | - binding.dependencies(); | 116 | + final localbinds = [if (binds != null) ...binds!]; |
117 | + | ||
118 | + final bindingsToBind = middlewareRunner | ||
119 | + .runOnBindingsStart(bindings.isNotEmpty ? bindings : localbinds); | ||
120 | + | ||
121 | + final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; | ||
122 | + | ||
123 | + if (bindingsToBind != null && bindingsToBind.isNotEmpty) { | ||
124 | + if (bindingsToBind is List<BindingsInterface>) { | ||
125 | + for (final item in bindingsToBind) { | ||
126 | + final dep = item.dependencies(); | ||
127 | + if (dep is List<Bind>) { | ||
128 | + _child = Binds( | ||
129 | + child: middlewareRunner.runOnPageBuilt(pageToBuild()), | ||
130 | + binds: dep, | ||
131 | + ); | ||
132 | + } | ||
133 | + } | ||
134 | + } else if (bindingsToBind is List<Bind>) { | ||
135 | + _child = Binds( | ||
136 | + child: middlewareRunner.runOnPageBuilt(pageToBuild()), | ||
137 | + binds: bindingsToBind, | ||
138 | + ); | ||
109 | } | 139 | } |
110 | } | 140 | } |
111 | 141 | ||
112 | - final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; | ||
113 | - _child = middlewareRunner.runOnPageBuilt(pageToBuild()); | ||
114 | - return _child!; | 142 | + return _child ??= middlewareRunner.runOnPageBuilt(pageToBuild()); |
115 | } | 143 | } |
116 | 144 | ||
117 | @override | 145 | @override |
1 | import 'package:flutter/cupertino.dart'; | 1 | import 'package:flutter/cupertino.dart'; |
2 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
3 | 3 | ||
4 | +import 'circular_reveal_clipper.dart'; | ||
5 | + | ||
4 | class LeftToRightFadeTransition { | 6 | class LeftToRightFadeTransition { |
5 | Widget buildTransitions( | 7 | Widget buildTransitions( |
6 | BuildContext context, | 8 | BuildContext context, |
@@ -184,3 +186,24 @@ class SizeTransitions { | @@ -184,3 +186,24 @@ class SizeTransitions { | ||
184 | ); | 186 | ); |
185 | } | 187 | } |
186 | } | 188 | } |
189 | + | ||
190 | +class CircularRevealTransition { | ||
191 | + Widget buildTransitions( | ||
192 | + BuildContext context, | ||
193 | + Curve? curve, | ||
194 | + Alignment? alignment, | ||
195 | + Animation<double> animation, | ||
196 | + Animation<double> secondaryAnimation, | ||
197 | + Widget child) { | ||
198 | + return ClipPath( | ||
199 | + clipper: CircularRevealClipper( | ||
200 | + fraction: animation.value, | ||
201 | + centerAlignment: Alignment.center, | ||
202 | + centerOffset: Offset.zero, | ||
203 | + minRadius: 0, | ||
204 | + maxRadius: 800, | ||
205 | + ), | ||
206 | + child: child, | ||
207 | + ); | ||
208 | + } | ||
209 | +} |
@@ -3,16 +3,16 @@ import 'package:flutter/widgets.dart'; | @@ -3,16 +3,16 @@ import 'package:flutter/widgets.dart'; | ||
3 | 3 | ||
4 | import '../../../get.dart'; | 4 | import '../../../get.dart'; |
5 | 5 | ||
6 | -class GetInformationParser extends RouteInformationParser<GetNavConfig> { | 6 | +class GetInformationParser extends RouteInformationParser<RouteDecoder> { |
7 | final String initialRoute; | 7 | final String initialRoute; |
8 | 8 | ||
9 | GetInformationParser({ | 9 | GetInformationParser({ |
10 | - this.initialRoute = '/', | 10 | + required this.initialRoute, |
11 | }) { | 11 | }) { |
12 | Get.log('GetInformationParser is created !'); | 12 | Get.log('GetInformationParser is created !'); |
13 | } | 13 | } |
14 | @override | 14 | @override |
15 | - SynchronousFuture<GetNavConfig> parseRouteInformation( | 15 | + SynchronousFuture<RouteDecoder> parseRouteInformation( |
16 | RouteInformation routeInformation, | 16 | RouteInformation routeInformation, |
17 | ) { | 17 | ) { |
18 | var location = routeInformation.location; | 18 | var location = routeInformation.location; |
@@ -26,22 +26,16 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { | @@ -26,22 +26,16 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { | ||
26 | 26 | ||
27 | Get.log('GetInformationParser: route location: $location'); | 27 | Get.log('GetInformationParser: route location: $location'); |
28 | 28 | ||
29 | - final matchResult = Get.routeTree.matchRoute(location ?? initialRoute); | 29 | + final routeName = location ?? initialRoute; |
30 | 30 | ||
31 | - return SynchronousFuture( | ||
32 | - GetNavConfig( | ||
33 | - currentTreeBranch: matchResult.treeBranch, | ||
34 | - location: location, | ||
35 | - state: routeInformation.state, | ||
36 | - ), | ||
37 | - ); | 31 | + return SynchronousFuture(RouteDecoder.fromRoute(routeName)); |
38 | } | 32 | } |
39 | 33 | ||
40 | @override | 34 | @override |
41 | - RouteInformation restoreRouteInformation(GetNavConfig config) { | 35 | + RouteInformation restoreRouteInformation(RouteDecoder config) { |
42 | return RouteInformation( | 36 | return RouteInformation( |
43 | - location: config.location, | ||
44 | - state: config.state, | 37 | + location: config.pageSettings?.name, |
38 | + state: null, | ||
45 | ); | 39 | ); |
46 | } | 40 | } |
47 | } | 41 | } |
1 | +import 'package:flutter/widgets.dart'; | ||
2 | + | ||
3 | +import '../../../get_instance/src/bindings_interface.dart'; | ||
4 | +import '../routes/get_route.dart'; | ||
5 | +import '../routes/transitions_type.dart'; | ||
6 | + | ||
7 | +/// Enables the user to customize the intended pop behavior | ||
8 | +/// | ||
9 | +/// Goes to either the previous _activePages entry or the previous page entry | ||
10 | +/// | ||
11 | +/// e.g. if the user navigates to these pages | ||
12 | +/// 1) /home | ||
13 | +/// 2) /home/products/1234 | ||
14 | +/// | ||
15 | +/// when popping on [History] mode, it will emulate a browser back button. | ||
16 | +/// | ||
17 | +/// so the new _activePages stack will be: | ||
18 | +/// 1) /home | ||
19 | +/// | ||
20 | +/// when popping on [Page] mode, it will only remove the last part of the route | ||
21 | +/// so the new _activePages stack will be: | ||
22 | +/// 1) /home | ||
23 | +/// 2) /home/products | ||
24 | +/// | ||
25 | +/// another pop will change the _activePages stack to: | ||
26 | +/// 1) /home | ||
27 | +enum PopMode { | ||
28 | + History, | ||
29 | + Page, | ||
30 | +} | ||
31 | + | ||
32 | +/// Enables the user to customize the behavior when pushing multiple routes that | ||
33 | +/// shouldn't be duplicates | ||
34 | +enum PreventDuplicateHandlingMode { | ||
35 | + /// Removes the _activePages entries until it reaches the old route | ||
36 | + PopUntilOriginalRoute, | ||
37 | + | ||
38 | + /// Simply don't push the new route | ||
39 | + DoNothing, | ||
40 | + | ||
41 | + /// Recommended - Moves the old route entry to the front | ||
42 | + /// | ||
43 | + /// With this mode, you guarantee there will be only one | ||
44 | + /// route entry for each location | ||
45 | + ReorderRoutes, | ||
46 | + | ||
47 | + Recreate, | ||
48 | +} | ||
49 | + | ||
50 | +mixin IGetNavigation { | ||
51 | + Future<T?> to<T>( | ||
52 | + Widget Function() page, { | ||
53 | + bool? opaque, | ||
54 | + Transition? transition, | ||
55 | + Curve? curve, | ||
56 | + Duration? duration, | ||
57 | + int? id, | ||
58 | + String? routeName, | ||
59 | + bool fullscreenDialog = false, | ||
60 | + dynamic arguments, | ||
61 | + List<BindingsInterface> bindings = const [], | ||
62 | + bool preventDuplicates = true, | ||
63 | + bool? popGesture, | ||
64 | + bool showCupertinoParallax = true, | ||
65 | + double Function(BuildContext context)? gestureWidth, | ||
66 | + }); | ||
67 | + | ||
68 | + Future<void> popModeUntil( | ||
69 | + String fullRoute, { | ||
70 | + PopMode popMode = PopMode.History, | ||
71 | + }); | ||
72 | + | ||
73 | + Future<T?> off<T>( | ||
74 | + Widget Function() page, { | ||
75 | + bool? opaque, | ||
76 | + Transition? transition, | ||
77 | + Curve? curve, | ||
78 | + Duration? duration, | ||
79 | + int? id, | ||
80 | + String? routeName, | ||
81 | + bool fullscreenDialog = false, | ||
82 | + dynamic arguments, | ||
83 | + List<BindingsInterface> bindings = const [], | ||
84 | + bool preventDuplicates = true, | ||
85 | + bool? popGesture, | ||
86 | + bool showCupertinoParallax = true, | ||
87 | + double Function(BuildContext context)? gestureWidth, | ||
88 | + }); | ||
89 | + | ||
90 | + Future<T?>? offAll<T>( | ||
91 | + Widget Function() page, { | ||
92 | + bool Function(GetPage route)? predicate, | ||
93 | + bool opaque = true, | ||
94 | + bool? popGesture, | ||
95 | + int? id, | ||
96 | + String? routeName, | ||
97 | + dynamic arguments, | ||
98 | + List<BindingsInterface> bindings = const [], | ||
99 | + bool fullscreenDialog = false, | ||
100 | + Transition? transition, | ||
101 | + Curve? curve, | ||
102 | + Duration? duration, | ||
103 | + bool showCupertinoParallax = true, | ||
104 | + double Function(BuildContext context)? gestureWidth, | ||
105 | + }); | ||
106 | + | ||
107 | + Future<T?> toNamed<T>( | ||
108 | + String page, { | ||
109 | + dynamic arguments, | ||
110 | + int? id, | ||
111 | + bool preventDuplicates = true, | ||
112 | + Map<String, String>? parameters, | ||
113 | + }); | ||
114 | + | ||
115 | + Future<T?> offNamed<T>( | ||
116 | + String page, { | ||
117 | + dynamic arguments, | ||
118 | + int? id, | ||
119 | + Map<String, String>? parameters, | ||
120 | + }); | ||
121 | + | ||
122 | + Future<T?>? offAllNamed<T>( | ||
123 | + String newRouteName, { | ||
124 | + // bool Function(GetPage route)? predicate, | ||
125 | + dynamic arguments, | ||
126 | + int? id, | ||
127 | + Map<String, String>? parameters, | ||
128 | + }); | ||
129 | + | ||
130 | + Future<T?>? offNamedUntil<T>( | ||
131 | + String page, { | ||
132 | + bool Function(GetPage route)? predicate, | ||
133 | + dynamic arguments, | ||
134 | + int? id, | ||
135 | + Map<String, String>? parameters, | ||
136 | + }); | ||
137 | + | ||
138 | + Future<T?> toNamedAndOffUntil<T>( | ||
139 | + String page, | ||
140 | + bool Function(GetPage) predicate, [ | ||
141 | + Object? data, | ||
142 | + ]); | ||
143 | + | ||
144 | + Future<T?> offUntil<T>( | ||
145 | + Widget Function() page, | ||
146 | + bool Function(GetPage) predicate, [ | ||
147 | + Object? arguments, | ||
148 | + ]); | ||
149 | + | ||
150 | + void back<T>([T? result]); | ||
151 | + | ||
152 | + Future<R?> backAndtoNamed<T, R>(String page, {T? result, Object? arguments}); | ||
153 | + | ||
154 | + void backUntil(bool Function(GetPage) predicate); | ||
155 | + | ||
156 | + void goToUnknownPage([bool clearPages = true]); | ||
157 | +} |
1 | +import 'package:flutter/widgets.dart'; | ||
2 | + | ||
3 | +import '../../../get.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 | + String? restorationScopeId, | ||
15 | + }) : super( | ||
16 | + //keys should be optional | ||
17 | + key: key, | ||
18 | + initialRoute: initialRoute, | ||
19 | + onPopPage: onPopPage ?? | ||
20 | + (route, result) { | ||
21 | + final didPop = route.didPop(result); | ||
22 | + if (!didPop) { | ||
23 | + return false; | ||
24 | + } | ||
25 | + return true; | ||
26 | + }, | ||
27 | + onGenerateRoute: (settings) { | ||
28 | + final selectedPageList = | ||
29 | + pages.where((element) => element.name == settings.name); | ||
30 | + if (selectedPageList.isNotEmpty) { | ||
31 | + final selectedPage = selectedPageList.first; | ||
32 | + return GetPageRoute( | ||
33 | + page: selectedPage.page, | ||
34 | + settings: settings, | ||
35 | + ); | ||
36 | + } | ||
37 | + return null; | ||
38 | + }, | ||
39 | + reportsRouteUpdateToEngine: reportsRouteUpdateToEngine, | ||
40 | + restorationScopeId: restorationScopeId, | ||
41 | + pages: pages, | ||
42 | + observers: [ | ||
43 | + // GetObserver(), | ||
44 | + ...?observers, | ||
45 | + ], | ||
46 | + transitionDelegate: | ||
47 | + transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(), | ||
48 | + ); | ||
49 | + | ||
50 | + GetNavigator({ | ||
51 | + GlobalKey<NavigatorState>? key, | ||
52 | + bool Function(Route<dynamic>, dynamic)? onPopPage, | ||
53 | + required List<GetPage> pages, | ||
54 | + List<NavigatorObserver>? observers, | ||
55 | + bool reportsRouteUpdateToEngine = false, | ||
56 | + TransitionDelegate? transitionDelegate, | ||
57 | + String? initialRoute, | ||
58 | + String? restorationScopeId, | ||
59 | + }) : super( | ||
60 | + //keys should be optional | ||
61 | + key: key, | ||
62 | + initialRoute: initialRoute, | ||
63 | + onPopPage: onPopPage ?? | ||
64 | + (route, result) { | ||
65 | + final didPop = route.didPop(result); | ||
66 | + if (!didPop) { | ||
67 | + return false; | ||
68 | + } | ||
69 | + return true; | ||
70 | + }, | ||
71 | + reportsRouteUpdateToEngine: reportsRouteUpdateToEngine, | ||
72 | + restorationScopeId: restorationScopeId, | ||
73 | + pages: pages, | ||
74 | + observers: [ | ||
75 | + // GetObserver(null, Get.routing), | ||
76 | + HeroController(), | ||
77 | + ...?observers, | ||
78 | + ], | ||
79 | + transitionDelegate: | ||
80 | + transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(), | ||
81 | + ); | ||
82 | +} |
1 | +import 'dart:async'; | ||
2 | + | ||
1 | import 'package:flutter/cupertino.dart'; | 3 | import 'package:flutter/cupertino.dart'; |
2 | import 'package:flutter/foundation.dart'; | 4 | import 'package:flutter/foundation.dart'; |
3 | import 'package:flutter/material.dart'; | 5 | import 'package:flutter/material.dart'; |
4 | -import 'package:flutter/widgets.dart'; | ||
5 | 6 | ||
6 | -import '../../../get_core/src/get_main.dart'; | ||
7 | -import '../../../get_instance/get_instance.dart'; | 7 | +import '../../../get_instance/src/bindings_interface.dart'; |
8 | +import '../../../get_state_manager/src/simple/get_state.dart'; | ||
8 | import '../../get_navigation.dart'; | 9 | import '../../get_navigation.dart'; |
9 | -import 'custom_transition.dart'; | ||
10 | -import 'transitions_type.dart'; | ||
11 | 10 | ||
12 | class GetPage<T> extends Page<T> { | 11 | class GetPage<T> extends Page<T> { |
13 | final GetPageBuilder page; | 12 | final GetPageBuilder page; |
@@ -21,12 +20,14 @@ class GetPage<T> extends Page<T> { | @@ -21,12 +20,14 @@ class GetPage<T> extends Page<T> { | ||
21 | final bool maintainState; | 20 | final bool maintainState; |
22 | final bool opaque; | 21 | final bool opaque; |
23 | final double Function(BuildContext context)? gestureWidth; | 22 | final double Function(BuildContext context)? gestureWidth; |
24 | - final Bindings? binding; | ||
25 | - final List<Bindings> bindings; | 23 | + //final BindingsInterface? binding; |
24 | + final List<BindingsInterface> bindings; | ||
25 | + final List<Bind> binds; | ||
26 | final CustomTransition? customTransition; | 26 | final CustomTransition? customTransition; |
27 | final Duration? transitionDuration; | 27 | final Duration? transitionDuration; |
28 | final bool fullscreenDialog; | 28 | final bool fullscreenDialog; |
29 | final bool preventDuplicates; | 29 | final bool preventDuplicates; |
30 | + final Completer<T?>? completer; | ||
30 | // @override | 31 | // @override |
31 | // final LocalKey? key; | 32 | // final LocalKey? key; |
32 | 33 | ||
@@ -45,6 +46,8 @@ class GetPage<T> extends Page<T> { | @@ -45,6 +46,8 @@ class GetPage<T> extends Page<T> { | ||
45 | final GetPage? unknownRoute; | 46 | final GetPage? unknownRoute; |
46 | final bool showCupertinoParallax; | 47 | final bool showCupertinoParallax; |
47 | 48 | ||
49 | + final PreventDuplicateHandlingMode preventDuplicateHandlingMode; | ||
50 | + | ||
48 | GetPage({ | 51 | GetPage({ |
49 | required this.name, | 52 | required this.name, |
50 | required this.page, | 53 | required this.page, |
@@ -59,8 +62,8 @@ class GetPage<T> extends Page<T> { | @@ -59,8 +62,8 @@ class GetPage<T> extends Page<T> { | ||
59 | this.opaque = true, | 62 | this.opaque = true, |
60 | this.transitionDuration, | 63 | this.transitionDuration, |
61 | this.popGesture, | 64 | this.popGesture, |
62 | - this.binding, | ||
63 | this.bindings = const [], | 65 | this.bindings = const [], |
66 | + this.binds = const [], | ||
64 | this.transition, | 67 | this.transition, |
65 | this.customTransition, | 68 | this.customTransition, |
66 | this.fullscreenDialog = false, | 69 | this.fullscreenDialog = false, |
@@ -70,17 +73,22 @@ class GetPage<T> extends Page<T> { | @@ -70,17 +73,22 @@ class GetPage<T> extends Page<T> { | ||
70 | this.arguments, | 73 | this.arguments, |
71 | this.showCupertinoParallax = true, | 74 | this.showCupertinoParallax = true, |
72 | this.preventDuplicates = true, | 75 | this.preventDuplicates = true, |
76 | + this.preventDuplicateHandlingMode = | ||
77 | + PreventDuplicateHandlingMode.ReorderRoutes, | ||
78 | + this.completer, | ||
79 | + LocalKey? key, | ||
73 | }) : path = _nameToRegex(name), | 80 | }) : path = _nameToRegex(name), |
74 | assert(name.startsWith('/'), | 81 | assert(name.startsWith('/'), |
75 | 'It is necessary to start route name [$name] with a slash: /$name'), | 82 | 'It is necessary to start route name [$name] with a slash: /$name'), |
76 | super( | 83 | super( |
77 | - key: ValueKey(name), | 84 | + key: key ?? ValueKey(name), |
78 | name: name, | 85 | name: name, |
79 | - arguments: Get.arguments, | 86 | + // arguments: Get.arguments, |
80 | ); | 87 | ); |
81 | // settings = RouteSettings(name: name, arguments: Get.arguments); | 88 | // settings = RouteSettings(name: name, arguments: Get.arguments); |
82 | 89 | ||
83 | GetPage<T> copy({ | 90 | GetPage<T> copy({ |
91 | + LocalKey? key, | ||
84 | String? name, | 92 | String? name, |
85 | GetPageBuilder? page, | 93 | GetPageBuilder? page, |
86 | bool? popGesture, | 94 | bool? popGesture, |
@@ -91,13 +99,14 @@ class GetPage<T> extends Page<T> { | @@ -91,13 +99,14 @@ class GetPage<T> extends Page<T> { | ||
91 | Alignment? alignment, | 99 | Alignment? alignment, |
92 | bool? maintainState, | 100 | bool? maintainState, |
93 | bool? opaque, | 101 | bool? opaque, |
94 | - Bindings? binding, | ||
95 | - List<Bindings>? bindings, | 102 | + List<BindingsInterface>? bindings, |
103 | + // BindingsInterface? binding, | ||
104 | + List<Bind>? binds, | ||
96 | CustomTransition? customTransition, | 105 | CustomTransition? customTransition, |
97 | Duration? transitionDuration, | 106 | Duration? transitionDuration, |
98 | bool? fullscreenDialog, | 107 | bool? fullscreenDialog, |
99 | RouteSettings? settings, | 108 | RouteSettings? settings, |
100 | - List<GetPage>? children, | 109 | + List<GetPage<T>>? children, |
101 | GetPage? unknownRoute, | 110 | GetPage? unknownRoute, |
102 | List<GetMiddleware>? middlewares, | 111 | List<GetMiddleware>? middlewares, |
103 | bool? preventDuplicates, | 112 | bool? preventDuplicates, |
@@ -105,8 +114,10 @@ class GetPage<T> extends Page<T> { | @@ -105,8 +114,10 @@ class GetPage<T> extends Page<T> { | ||
105 | bool? participatesInRootNavigator, | 114 | bool? participatesInRootNavigator, |
106 | Object? arguments, | 115 | Object? arguments, |
107 | bool? showCupertinoParallax, | 116 | bool? showCupertinoParallax, |
117 | + Completer<T?>? completer, | ||
108 | }) { | 118 | }) { |
109 | return GetPage( | 119 | return GetPage( |
120 | + key: key ?? this.key, | ||
110 | participatesInRootNavigator: | 121 | participatesInRootNavigator: |
111 | participatesInRootNavigator ?? this.participatesInRootNavigator, | 122 | participatesInRootNavigator ?? this.participatesInRootNavigator, |
112 | preventDuplicates: preventDuplicates ?? this.preventDuplicates, | 123 | preventDuplicates: preventDuplicates ?? this.preventDuplicates, |
@@ -120,8 +131,8 @@ class GetPage<T> extends Page<T> { | @@ -120,8 +131,8 @@ class GetPage<T> extends Page<T> { | ||
120 | alignment: alignment ?? this.alignment, | 131 | alignment: alignment ?? this.alignment, |
121 | maintainState: maintainState ?? this.maintainState, | 132 | maintainState: maintainState ?? this.maintainState, |
122 | opaque: opaque ?? this.opaque, | 133 | opaque: opaque ?? this.opaque, |
123 | - binding: binding ?? this.binding, | ||
124 | bindings: bindings ?? this.bindings, | 134 | bindings: bindings ?? this.bindings, |
135 | + binds: binds ?? this.binds, | ||
125 | customTransition: customTransition ?? this.customTransition, | 136 | customTransition: customTransition ?? this.customTransition, |
126 | transitionDuration: transitionDuration ?? this.transitionDuration, | 137 | transitionDuration: transitionDuration ?? this.transitionDuration, |
127 | fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog, | 138 | fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog, |
@@ -132,6 +143,7 @@ class GetPage<T> extends Page<T> { | @@ -132,6 +143,7 @@ class GetPage<T> extends Page<T> { | ||
132 | arguments: arguments ?? this.arguments, | 143 | arguments: arguments ?? this.arguments, |
133 | showCupertinoParallax: | 144 | showCupertinoParallax: |
134 | showCupertinoParallax ?? this.showCupertinoParallax, | 145 | showCupertinoParallax ?? this.showCupertinoParallax, |
146 | + completer: completer ?? this.completer, | ||
135 | ); | 147 | ); |
136 | } | 148 | } |
137 | 149 | ||
@@ -167,6 +179,21 @@ class GetPage<T> extends Page<T> { | @@ -167,6 +179,21 @@ class GetPage<T> extends Page<T> { | ||
167 | 179 | ||
168 | return PathDecoded(RegExp('^$stringPath\$'), keys); | 180 | return PathDecoded(RegExp('^$stringPath\$'), keys); |
169 | } | 181 | } |
182 | + | ||
183 | + @override | ||
184 | + bool operator ==(Object other) { | ||
185 | + if (identical(this, other)) return true; | ||
186 | + return other is GetPage<T> && other.key == key; | ||
187 | + } | ||
188 | + | ||
189 | + @override | ||
190 | + String toString() => | ||
191 | + '${objectRuntimeType(this, 'Page')}("$name", $key, $arguments)'; | ||
192 | + | ||
193 | + @override | ||
194 | + int get hashCode { | ||
195 | + return key.hashCode; | ||
196 | + } | ||
170 | } | 197 | } |
171 | 198 | ||
172 | @immutable | 199 | @immutable |
-
Please register or login to post a comment