sejun
Committed by GitHub

Merge branch 'jonataslaw:master' into master

Showing 59 changed files with 2150 additions and 1094 deletions

Too many changes to show.

To preserve performance only 59 of 59+ files are displayed.

No preview for this file type
@@ -23,7 +23,7 @@ jobs: @@ -23,7 +23,7 @@ jobs:
23 # https://github.com/marketplace/actions/flutter-action 23 # https://github.com/marketplace/actions/flutter-action
24 - uses: subosito/flutter-action@v1 24 - uses: subosito/flutter-action@v1
25 with: 25 with:
26 - flutter-version: "2.0.2" 26 + flutter-version: "2.2.3"
27 channel: "stable" 27 channel: "stable"
28 - run: flutter pub get 28 - run: flutter pub get
29 #- run: flutter analyze 29 #- run: flutter analyze
  1 + ## [4.2.4]
  2 +- Added anchorRoute and filterPages to
  3 +
  4 +
  5 + // anchorRoute: '/',
  6 + // filterPages:
  7 +
  8 +
  9 +## [4.2.4]
  10 +- Fix Get.offAll removing GetxServices from memory
  11 +
  12 +## [4.2.3]
  13 +- Fix back button on navigator 2
  14 +- Added parameters and arguments to Get.rootDelegate
  15 +
  16 +## [4.2.1]
  17 +- Remove [] from docs to try fix pub score
  18 +
  19 +## [4.2.0] - Big update
  20 +
  21 +This update fixes important bugs as well as integrates with Navigator 2. It also adds GetRouterOutlet, similar to angular RouterOutlet thanks to @ahmednfwela. Also, the documentation translation for Vietnamese (@khangahs) has been added, making the GetX documentation available for 11 different languages, which is just fantastic for any opensource project. GetX has achieved more than 5.4k likes from the pub, and more than 4k stars on github, has videos about it with 48k on youtube, and has communities in the 4 hemispheres of the earth, besides having a large list of contributors as you see bellow. We're all happy to facilitate development with dart and flutter, and that making programming hassle-free has been taken around the world.
  22 +
  23 +Changes in this version:
  24 +
  25 +- Fix: Navigating to the same page with Get.offNamed does not delete the controller from that page using Get.lazyPut.
  26 +
  27 +- Fix Readme GetMiddleware typos
  28 +by @nivisi
  29 +
  30 +- Fix url replace error
  31 +by @KevinZhang19870314
  32 +
  33 +- Changed response default encoding from latin1 to utf8
  34 +by @heftekharm
  35 +
  36 +- Add Duration in ExtensionBottomSheet
  37 +by @chanonpingpong
  38 +
  39 +- Added compatibility with dart-lang/mockito
  40 +by @lifez
  41 +
  42 +- Added extensions methods to convert value in percent value
  43 +by @kauemurakami
  44 +
  45 +- Set darkTheme equal theme when darkTheme is null
  46 +by @eduardoFlorence
  47 +
  48 +- Add padding to 'defaultDialog'
  49 +by @KevinZhang19870314
  50 +
  51 +- GraphQLResponse inherit Response info
  52 +by @jasonlaw
  53 +
  54 +- Fix Redundant concatenating base url
  55 +by @jasonlaw
  56 +
  57 +- Add content type and length into the headers when the content type is 'application/x-www-form-urlencoded'
  58 +by @calvingit
  59 +
  60 +- Make withCredentials configurable
  61 +by @jasonlaw
  62 +
  63 +- Fix flutter 2.0 error
  64 +by @yunchiri
  65 +
  66 +- Allow deleting all registered instances
  67 +by @lemps
  68 +
  69 +- Refactor/rx interface notify children
  70 +@by kranfix
  71 +
  72 +- Fixed parameter parsing and middleware sorting
  73 +by @ahmednfwela
  74 +
  75 +- Improvements to router outlet
  76 +by @ahmednfwela
  77 +
  78 +- Minor improvements and bug fixes
  79 +by @ahmednfwela
  80 +
  81 +- Adding route guards and improving navigation
  82 +by @ahmednfwela
  83 +
  84 +- Fix RxInterface.proxy losing its previous value on exception
  85 +by @WillowWisp
  86 +
  87 +- Added dispose() for bottomSheet.
  88 +by @furkankurt
  89 +
  90 +- Added Pull request template
  91 +by @unacorbatanegra
  92 +
  93 +- Fix and update documentation:
  94 +@Farid566,
  95 +@galaxykhh,
  96 +@arslee07,
  97 +@GoStaRoff,
  98 +@BondarenkoArtur,
  99 +@denisrudnei,
  100 +@Charly6596,
  101 +@nateshmbhat,
  102 +@hrithikrtiwari,
  103 +@Undeadlol1,
  104 +@rws08,
  105 +@inuyashaaa,
  106 +@broccolism,
  107 +@aadarshadhakalg,
  108 +@ZeroMinJeon
  109 +
  110 +
1 ## [4.1.4] 111 ## [4.1.4]
2 - Adjust operator + and - to RxInt (@eduardoflorence) 112 - Adjust operator + and - to RxInt (@eduardoflorence)
3 - Fix dark theme (@eduardoflorence) 113 - Fix dark theme (@eduardoflorence)
1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png) 1 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/get.png)
2 2
3 -**언어: [영어](README.md), [베트남어](README-vi.md), [인도네시아어](README.id-ID.md), [우르두어](README.ur-PK.md), [중국어](README.zh-cn.md), [브라질 포르투칼어](README.pt-br.md), [스페인어](README-es.md), [러시아어](README.ru.md), [폴란드어](README.pl.md), 한국어(이파일), [프랑스어](README-fr.md)**  
4 -  
5 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get) 3 [![pub package](https://img.shields.io/pub/v/get.svg?label=get&color=blue)](https://pub.dev/packages/get)
6 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score) 4 [![likes](https://badges.bar/get/likes)](https://pub.dev/packages/get/score)
7 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg) 5 ![building](https://github.com/jonataslaw/get/workflows/build/badge.svg)
@@ -16,6 +14,26 @@ @@ -16,6 +14,26 @@
16 14
17 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png) 15 ![](https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png)
18 16
  17 +
  18 +<div align="center">
  19 +
  20 +**Languages:**
  21 +
  22 +
  23 +[![영어](https://img.shields.io/badge/Language-English-blueviolet?style=for-the-badge)](README.md)
  24 +[![베트남어](https://img.shields.io/badge/Language-Vietnamese-blueviolet?style=for-the-badge)](README-vi.md)
  25 +[![인도네시아어](https://img.shields.io/badge/Language-Indonesian-blueviolet?style=for-the-badge)](README.id-ID.md)
  26 +[![우르두어](https://img.shields.io/badge/Language-Urdu-blueviolet?style=for-the-badge)](README.ur-PK.md)
  27 +[![중국어](https://img.shields.io/badge/Language-Chinese-blueviolet?style=for-the-badge)](README.zh-cn.md)
  28 +[![포르투칼어](https://img.shields.io/badge/Language-Portuguese-blueviolet?style=for-the-badge)](README.pt-br.md)
  29 +[![스페인어](https://img.shields.io/badge/Language-Spanish-blueviolet?style=for-the-badge)](README-es.md)
  30 +[![러시아어](https://img.shields.io/badge/Language-Russian-blueviolet?style=for-the-badge)](README.ru.md)
  31 +[![폴란드어](https://img.shields.io/badge/Language-Polish-blueviolet?style=for-the-badge)](README.pl.md)
  32 +[![한국어](https://img.shields.io/badge/Language-Korean-blueviolet?style=for-the-badge)](README.ko-kr.md)
  33 +[![프랑스어](https://img.shields.io/badge/Language-French-blueviolet?style=for-the-badge)](README-fr.md)
  34 +
  35 +</div>
  36 +
19 - [Get에 대하여](#get에-대하여) 37 - [Get에 대하여](#get에-대하여)
20 - [설치](#설치) 38 - [설치](#설치)
21 - [GetX를 사용한 Counter 앱](#getx를-사용한-counter-앱) 39 - [GetX를 사용한 Counter 앱](#getx를-사용한-counter-앱)
@@ -53,6 +71,8 @@ @@ -53,6 +71,8 @@
53 - [ObxValue](#obxvalue) 71 - [ObxValue](#obxvalue)
54 - [유용한 팁](#유용한-팁) 72 - [유용한 팁](#유용한-팁)
55 - [GetView](#getview) 73 - [GetView](#getview)
  74 + - [GetResponsiveView](#getresponsiveview)
  75 + - [사용 방법](#사용-방법)
56 - [GetWidget](#getwidget) 76 - [GetWidget](#getwidget)
57 - [GetxService](#getxservice) 77 - [GetxService](#getxservice)
58 - [2.0의 주요 변경점](#20의-주요-변경점) 78 - [2.0의 주요 변경점](#20의-주요-변경점)
@@ -71,9 +91,11 @@ @@ -71,9 +91,11 @@
71 - **성능:** GetX는 성능과 최소한의 리소스 소비에 중점을 둡니다. GetX는 Streams나 ChangeNotifier를 사용하지 않습니다. 91 - **성능:** GetX는 성능과 최소한의 리소스 소비에 중점을 둡니다. GetX는 Streams나 ChangeNotifier를 사용하지 않습니다.
72 92
73 - **생산성:** GetX는 쉽고 친숙한 구문을 사용합니다. 원하시는 것보다 Getx에는 항상 더 쉬운 방법이 있습니다. 개발 시간을 아끼고 애플리케이션을 최대 성능으로 제공할 수 있습니다. 93 - **생산성:** GetX는 쉽고 친숙한 구문을 사용합니다. 원하시는 것보다 Getx에는 항상 더 쉬운 방법이 있습니다. 개발 시간을 아끼고 애플리케이션을 최대 성능으로 제공할 수 있습니다.
  94 +
74 일반적으로 개발자는 메모리에서 컨트롤러들을 제거하는 데 관심을 가져야합니다. GetX에서는 리소스가 기본적으로 사용되지 않으면 메모리에서 제거되므로 필요하지 않습니다. 만약 메모리에 유지하려면 종속성에서 "permanent : true"를 명시적으로 선언해야합니다. 이렇게하면 시간을 절약 할 수있을뿐만 아니라 불필요한 메모리 종속성이 발생할 위험이 줄어 듭니다. 종속성은 기본적으로 lazy로 로드됩니다. 95 일반적으로 개발자는 메모리에서 컨트롤러들을 제거하는 데 관심을 가져야합니다. GetX에서는 리소스가 기본적으로 사용되지 않으면 메모리에서 제거되므로 필요하지 않습니다. 만약 메모리에 유지하려면 종속성에서 "permanent : true"를 명시적으로 선언해야합니다. 이렇게하면 시간을 절약 할 수있을뿐만 아니라 불필요한 메모리 종속성이 발생할 위험이 줄어 듭니다. 종속성은 기본적으로 lazy로 로드됩니다.
75 96
76 - **조직화:** GetX는 화면, 프레젠테이션 로직, 비즈니스 로직, 종속성 주입 및 네비게이션을 완전히 분리 할 수 있습니다. 라우트간 전환을 하는데에 컨텍스트가 필요하지 않아 위젯 트리(시각객체)에 독립적입니다. inheritedWidget을 통해 컨트롤러/블록에 접근하는 데 컨텍스트가 필요하지 않아 시각화 계층에서 프레젠테이션 로직과 비즈니스 로직을 완전히 분리됩니다. 이 GetX는 자체 종속성 주입 기능을 사용하여 DI를 뷰에서 완전히 분리하기 때문에 다중 Provider를 통해 위젯 트리에서 컨트롤러/모델/블록으로 주입 할 필요가 없습니다. 97 - **조직화:** GetX는 화면, 프레젠테이션 로직, 비즈니스 로직, 종속성 주입 및 네비게이션을 완전히 분리 할 수 있습니다. 라우트간 전환을 하는데에 컨텍스트가 필요하지 않아 위젯 트리(시각객체)에 독립적입니다. inheritedWidget을 통해 컨트롤러/블록에 접근하는 데 컨텍스트가 필요하지 않아 시각화 계층에서 프레젠테이션 로직과 비즈니스 로직을 완전히 분리됩니다. 이 GetX는 자체 종속성 주입 기능을 사용하여 DI를 뷰에서 완전히 분리하기 때문에 다중 Provider를 통해 위젯 트리에서 컨트롤러/모델/블록으로 주입 할 필요가 없습니다.
  98 +
77 GetX를 사용하면 기본적으로 클린 코드를 가지게 되어 애플리케이션의 각 기능을 쉽게 찾을 수있습니다. 이것은 유지 보수를 용이하게 하며 모듈의 공유가 가능하고 Flutter에서는 생각할 수 없었던 것들도 전부 가능합니다. 99 GetX를 사용하면 기본적으로 클린 코드를 가지게 되어 애플리케이션의 각 기능을 쉽게 찾을 수있습니다. 이것은 유지 보수를 용이하게 하며 모듈의 공유가 가능하고 Flutter에서는 생각할 수 없었던 것들도 전부 가능합니다.
78 BLoC은 Flutter에서 코드를 구성하기 위한 시작점으로 비즈니스 로직과 시각객체를 분리합니다. Getx는 비즈니스 로직 뿐만 아니라 프레젠테이션 로직을 분리하는 자연스러운 진화입니다. 추가로 종속성 주입과 라우트 또한 분리되고 데이터 계층이 모두로부터 분리됩니다. Hello World를 구현하는 것보다 더 쉽게 모든 것이 어디 있는지 알수 있습니다. 100 BLoC은 Flutter에서 코드를 구성하기 위한 시작점으로 비즈니스 로직과 시각객체를 분리합니다. Getx는 비즈니스 로직 뿐만 아니라 프레젠테이션 로직을 분리하는 자연스러운 진화입니다. 추가로 종속성 주입과 라우트 또한 분리되고 데이터 계층이 모두로부터 분리됩니다. Hello World를 구현하는 것보다 더 쉽게 모든 것이 어디 있는지 알수 있습니다.
79 Flutter SDK와 함께 GetX를 사용하면 가장 쉽고 실용적이며 확장 가능한 고성능 어플리케이션을 만들수 있습니다. 초보자에게는 쉬우며 전문가에게는 정확하고 완벽하게 동작하는 대규모 생태계가 함께합니다. 안전하고 안정적이며 업데이트되고 기본 Flutter SDK에 없는 광범위한 API 빌드를 제공합니다. 101 Flutter SDK와 함께 GetX를 사용하면 가장 쉽고 실용적이며 확장 가능한 고성능 어플리케이션을 만들수 있습니다. 초보자에게는 쉬우며 전문가에게는 정확하고 완벽하게 동작하는 대규모 생태계가 함께합니다. 안전하고 안정적이며 업데이트되고 기본 Flutter SDK에 없는 광범위한 API 빌드를 제공합니다.
@@ -85,7 +107,8 @@ @@ -85,7 +107,8 @@
85 107
86 **추가로 [Get CLI](https://github.com/jonataslaw/get_cli)를 프런트엔드와 서버 양쪽에서 사용하면 전체 개발 프로세스를 자동화 할 수 있습니다.** 108 **추가로 [Get CLI](https://github.com/jonataslaw/get_cli)를 프런트엔드와 서버 양쪽에서 사용하면 전체 개발 프로세스를 자동화 할 수 있습니다.**
87 109
88 -**추가로 생산성 향상을 위해 [VSCode 확장](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)과 [Android Studio/Intellij 확장](https://plugins.jetbrains.com/plugin/14975-getx-snippets)이 있습니다.** 110 +**추가로 생산성 향상을 위해
  111 +[VSCode 확장](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)[Android Studio/Intellij 확장](https://plugins.jetbrains.com/plugin/14975-getx-snippets)이 있습니다.**
89 112
90 # 설치 113 # 설치
91 114
@@ -114,7 +137,6 @@ void main() => runApp(GetMaterialApp(home: Home())); @@ -114,7 +137,6 @@ void main() => runApp(GetMaterialApp(home: Home()));
114 ``` 137 ```
115 138
116 - 주석: 이는 Flutter의 MaterialApp을 변경하지 않으며 GetMaterialApp 또한 수정 된 MaterialApp이 아니고, 기본 MaterialApp을 자식으로 갖는 사전 구성된 위젯 일뿐입니다. 수동으로 구성 할 수 있지만 반드시 필요한 것은 아닙니다. GetMaterialApp은 라우트를 생성하고 추가하며, 번역을 추가하고, 라우트 탐색에 필요한 모든 것을 추가합니다. 만약 상태 관리 또는 종속성 관리에만 Get을 사용하는 경우 GetMaterialApp을 사용할 필요가 없습니다. GetMaterialApp은 라우트, 스택바, 국제화, bottomSheets, 다이얼로그 및 컨텍스트 부재와 라우트에 연관된 상위 api들에 필요합니다. 139 - 주석: 이는 Flutter의 MaterialApp을 변경하지 않으며 GetMaterialApp 또한 수정 된 MaterialApp이 아니고, 기본 MaterialApp을 자식으로 갖는 사전 구성된 위젯 일뿐입니다. 수동으로 구성 할 수 있지만 반드시 필요한 것은 아닙니다. GetMaterialApp은 라우트를 생성하고 추가하며, 번역을 추가하고, 라우트 탐색에 필요한 모든 것을 추가합니다. 만약 상태 관리 또는 종속성 관리에만 Get을 사용하는 경우 GetMaterialApp을 사용할 필요가 없습니다. GetMaterialApp은 라우트, 스택바, 국제화, bottomSheets, 다이얼로그 및 컨텍스트 부재와 라우트에 연관된 상위 api들에 필요합니다.
117 -  
118 - 주석²: 이 단계는 라우트 관리 (`Get.to ()`,`Get.back ()` 등)를 사용하려는 경우에만 필요합니다. 사용하지 않을 경우 1 단계를 수행 할 필요가 없습니다. 140 - 주석²: 이 단계는 라우트 관리 (`Get.to ()`,`Get.back ()` 등)를 사용하려는 경우에만 필요합니다. 사용하지 않을 경우 1 단계를 수행 할 필요가 없습니다.
119 141
120 - 2 단계: 142 - 2 단계:
@@ -339,6 +361,34 @@ class Messages extends Translations { @@ -339,6 +361,34 @@ class Messages extends Translations {
339 Text('title'.tr); 361 Text('title'.tr);
340 ``` 362 ```
341 363
  364 +#### 단수와 복수의 번역 사용법
  365 +
  366 +```dart
  367 +var products = [];
  368 +Text('singularKey'.trPlural('pluralKey', products.length, Args));
  369 +```
  370 +
  371 +#### 파라미터로 번역 사용하는 방법
  372 +
  373 +```dart
  374 +import 'package:get/get.dart';
  375 +
  376 +
  377 +Map<String, Map<String, String>> get keys => {
  378 + 'en_US': {
  379 + 'logged_in': 'logged in as @name with email @email',
  380 + },
  381 + 'es_ES': {
  382 + 'logged_in': 'iniciado sesión como @name con e-mail @email',
  383 + }
  384 +};
  385 +
  386 +Text('logged_in'.trParams({
  387 + 'name': 'Jhon',
  388 + 'email': 'jhon@example.com'
  389 + }));
  390 +```
  391 +
342 ### 지역화 392 ### 지역화
343 393
344 `GetMaterialApp`의 파라미터를 전달하여 지역과 번역어를 정의합니다. 394 `GetMaterialApp`의 파라미터를 전달하여 지역과 번역어를 정의합니다.
@@ -392,9 +442,11 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); @@ -392,9 +442,11 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
392 `.darkmode`가 활성화 될때 _light theme_ 로 바뀔것 이고 _light theme_ 가 활성화되면 _dark theme_ 로 변경될 것입니다. 442 `.darkmode`가 활성화 될때 _light theme_ 로 바뀔것 이고 _light theme_ 가 활성화되면 _dark theme_ 로 변경될 것입니다.
393 443
394 ## GetConnect 444 ## GetConnect
  445 +
395 GetConnect는 http나 websockets으로 프론트와 백엔드의 통신을 위한 쉬운 방법입니다. 446 GetConnect는 http나 websockets으로 프론트와 백엔드의 통신을 위한 쉬운 방법입니다.
396 447
397 ### 기본 구성 448 ### 기본 구성
  449 +
398 GetConnect를 간단하게 확장하고 Rest API나 websockets의 GET/POST/PUT/DELETE/SOCKET 메서드를 사용할 수 있습니다. 450 GetConnect를 간단하게 확장하고 Rest API나 websockets의 GET/POST/PUT/DELETE/SOCKET 메서드를 사용할 수 있습니다.
399 451
400 ```dart 452 ```dart
@@ -417,7 +469,9 @@ class UserProvider extends GetConnect { @@ -417,7 +469,9 @@ class UserProvider extends GetConnect {
417 } 469 }
418 } 470 }
419 ``` 471 ```
  472 +
420 ### 커스텀 구성 473 ### 커스텀 구성
  474 +
421 GetConnect는 고도로 커스텀화 할 수 있습니다. base Url을 정의하고 응답자 및 요청을 수정하고 인증자를 정의할 수 있습니다. 그리고 인증 횟수까지 정의 할 수 있습니다. 더해서 추가 구성없이 모델로 응답을 변형시킬 수 있는 표준 디코더 정의도 가능합니다. 475 GetConnect는 고도로 커스텀화 할 수 있습니다. base Url을 정의하고 응답자 및 요청을 수정하고 인증자를 정의할 수 있습니다. 그리고 인증 횟수까지 정의 할 수 있습니다. 더해서 추가 구성없이 모델로 응답을 변형시킬 수 있는 표준 디코더 정의도 가능합니다.
422 476
423 ```dart 477 ```dart
@@ -427,7 +481,8 @@ class HomeProvider extends GetConnect { @@ -427,7 +481,8 @@ class HomeProvider extends GetConnect {
427 // 모든 요청은 jsonEncode로 CasesModel.fromJson()를 거칩니다. 481 // 모든 요청은 jsonEncode로 CasesModel.fromJson()를 거칩니다.
428 httpClient.defaultDecoder = CasesModel.fromJson; 482 httpClient.defaultDecoder = CasesModel.fromJson;
429 httpClient.baseUrl = 'https://api.covid19api.com'; 483 httpClient.baseUrl = 'https://api.covid19api.com';
430 - // baseUrl = 'https://api.covid19api.com'; // [httpClient] 인스턴트 없이 사용하는경우 Http와 websockets의 baseUrl 정의 484 + // baseUrl = 'https://api.covid19api.com';
  485 + // [httpClient] 인스턴트 없이 사용하는경우 Http와 websockets의 baseUrl 정의
431 486
432 // 모든 요청의 헤더에 'apikey' 속성을 첨부합니다. 487 // 모든 요청의 헤더에 'apikey' 속성을 첨부합니다.
433 httpClient.addRequestModifier((request) { 488 httpClient.addRequestModifier((request) {
@@ -482,6 +537,7 @@ final middlewares = [ @@ -482,6 +537,7 @@ final middlewares = [
482 GetMiddleware(priority: -8), 537 GetMiddleware(priority: -8),
483 ]; 538 ];
484 ``` 539 ```
  540 +
485 이 Middleware는 다음 순서로 실행됩니다. **-8 => 2 => 4 => 5** 541 이 Middleware는 다음 순서로 실행됩니다. **-8 => 2 => 4 => 5**
486 542
487 ### Redirect 543 ### Redirect
@@ -761,7 +817,8 @@ ValueBuilder<bool>( @@ -761,7 +817,8 @@ ValueBuilder<bool>(
761 817
762 #### ObxValue 818 #### ObxValue
763 819
764 -[`ValueBuilder`](#valuebuilder)와 비슷하지만 Rx 인스턴스(마법같은 .obs를 기억하세요)를 전달하고 자동적으로 업데이트되는 반응형 버전입니다... 놀랍지 않습니까? 820 +[`ValueBuilder`](#valuebuilder)와 비슷하지만 Rx 인스턴스(마법같은 .obs를 기억하세요)를 전달하고
  821 +자동적으로 업데이트되는 반응형 버전입니다... 놀랍지 않습니까?
765 822
766 ```dart 823 ```dart
767 ObxValue((data) => Switch( 824 ObxValue((data) => Switch(
@@ -877,6 +934,55 @@ user.update((value){ @@ -877,6 +934,55 @@ user.update((value){
877 934
878 print( user ); 935 print( user );
879 ``` 936 ```
  937 +## StateMixin
  938 +
  939 +`UI` 상태를 처리하는 또 다른 방법은 `StateMixin<T>` 를 사용하는 것입니다.
  940 +이를 구현하려면 `with`를 사용하여 `StateMixin<T>`을 추가하고
  941 +T 모델을 허용하는 컨트롤러에 연결합니다.
  942 +
  943 +``` dart
  944 +class Controller extends GetController with StateMixin<User>{}
  945 +```
  946 +
  947 +`change()` 메소드는 우리가 원할 때마다 State를 변경합니다.
  948 +다음과 같이 데이터와 상태를 전달하면 됩니다:
  949 +
  950 +```dart
  951 +change(data, status: RxStatus.success());
  952 +```
  953 +
  954 +RxStatus는 다음 상태를 허용합니다:
  955 +
  956 +``` dart
  957 +RxStatus.loading();
  958 +RxStatus.success();
  959 +RxStatus.empty();
  960 +RxStatus.error('message');
  961 +```
  962 +
  963 +UI에서 사용하는 방법:
  964 +
  965 +```dart
  966 +class OtherClass extends GetView<Controller> {
  967 + @override
  968 + Widget build(BuildContext context) {
  969 + return Scaffold(
  970 +
  971 + body: controller.obx(
  972 + (state)=>Text(state.name),
  973 +
  974 + // 여기에 사용자 정의 로딩 표시기를 넣을 수 있지만
  975 + // 기본값은 Center(child:CircularProgressIndicator()) 입니다
  976 + onLoading: CustomLoadingIndicator(),
  977 + onEmpty: Text('No data found'),
  978 +
  979 + // 여기에서도 자신의 오류 위젯을 설정할 수 있지만
  980 + // 기본값은 Center(child:Text(error)) 입니다
  981 + onError: (error)=>Text(error),
  982 + ),
  983 + );
  984 +}
  985 +```
880 986
881 #### GetView 987 #### GetView
882 988
@@ -901,6 +1007,29 @@ print( user ); @@ -901,6 +1007,29 @@ print( user );
901 } 1007 }
902 ``` 1008 ```
903 1009
  1010 +#### GetResponsiveView
  1011 +
  1012 +Extend this widget to build responsive view.
  1013 +this widget contains the `screen` property that have all
  1014 +information about the screen size and type.
  1015 +
  1016 +##### 사용 방법
  1017 +
  1018 +You have two options to build it.
  1019 +
  1020 +- with `builder` method you return the widget to build.
  1021 +- with methods `desktop`, `tablet`,`phone`, `watch`. the specific
  1022 + method will be built when the screen type matches the method
  1023 + when the screen is [ScreenType.Tablet] the `tablet` method
  1024 + will be exuded and so on.
  1025 + **Note:** If you use this method please set the property `alwaysUseBuilder` to `false`
  1026 +
  1027 +With `settings` property you can set the width limit for the screen types.
  1028 +
  1029 +![example](https://github.com/SchabanBo/get_page_example/blob/master/docs/Example.gif?raw=true)
  1030 +Code to this screen
  1031 +[code](https://github.com/SchabanBo/get_page_example/blob/master/lib/pages/responsive_example/responsive_view.dart)
  1032 +
904 #### GetWidget 1033 #### GetWidget
905 1034
906 대부분의 사람들이 이 위젯에대해 모르거나 사용법을 완전히 혼동합니다. 1035 대부분의 사람들이 이 위젯에대해 모르거나 사용법을 완전히 혼동합니다.
@@ -911,7 +1040,8 @@ _cache_ 이기 때문에 `const Stateless`가 될 수 없습니다. @@ -911,7 +1040,8 @@ _cache_ 이기 때문에 `const Stateless`가 될 수 없습니다.
911 1040
912 만약 **GetX**의 기능 중 또 다른 "흔하지 않은" 기능을 사용하는 경우:`Get.create()` 1041 만약 **GetX**의 기능 중 또 다른 "흔하지 않은" 기능을 사용하는 경우:`Get.create()`
913 1042
914 -`Get.create(()=>Controller())`가 `Get.find<Controller>()`을 호출할 때마다 새로운 `Controller`를 생성할 것 입니다. 1043 +`Get.create(()=>Controller())`가 `Get.find<Controller>()`을 호출할 때마다
  1044 +새로운 `Controller`를 생성할 것 입니다.
915 1045
916 여기서 `GetWidget`이 빛나게 됩니다... 예를 들어 Todo 리스트를 유지하려고 사용할 때 입니다. 1046 여기서 `GetWidget`이 빛나게 됩니다... 예를 들어 Todo 리스트를 유지하려고 사용할 때 입니다.
917 위젯이 "재구성"될때 동일한 controller 인스턴스를 유지할 것입니다. 1047 위젯이 "재구성"될때 동일한 controller 인스턴스를 유지할 것입니다.
@@ -919,14 +1049,14 @@ _cache_ 이기 때문에 `const Stateless`가 될 수 없습니다. @@ -919,14 +1049,14 @@ _cache_ 이기 때문에 `const Stateless`가 될 수 없습니다.
919 #### GetxService 1049 #### GetxService
920 1050
921 이 클래스틑 `GetxController`와 같이 동일한 생성주기(`onInit()`, `onReady()`, `onClose()`)를 공유합니다. 1051 이 클래스틑 `GetxController`와 같이 동일한 생성주기(`onInit()`, `onReady()`, `onClose()`)를 공유합니다.
922 -하지만 이안에 "로직"은 없습니다. 단지 **GetX** 종속성 주입 시스템이 하위클래스를 메모리에서 삭제할 수 없음을 알립니다. 1052 +하지만 이안에 "로직"은 없습니다. 단지 **GetX** 종속성 주입 시스템이 하위클래스를 메모리에서
  1053 +**삭제할 수 없음**을 알립니다.
923 1054
924 그래서 `Get.find()`로 활성화하고 항상 접근하는 "서비스들"을 유지하는데 매우 유용합니다. : 1055 그래서 `Get.find()`로 활성화하고 항상 접근하는 "서비스들"을 유지하는데 매우 유용합니다. :
925 `ApiService`, `StorageService`, `CacheService`. 1056 `ApiService`, `StorageService`, `CacheService`.
926 1057
927 ```dart 1058 ```dart
928 Future<void> main() async { 1059 Future<void> main() async {
929 - WidgetsFlutterBinding.ensureInitialized()  
930 await initServices(); /// 서비스들 초기화를 기다림. 1060 await initServices(); /// 서비스들 초기화를 기다림.
931 runApp(SomeApp()); 1061 runApp(SomeApp());
932 } 1062 }
@@ -964,7 +1094,8 @@ class SettingsService extends GetxService { @@ -964,7 +1094,8 @@ class SettingsService extends GetxService {
964 ``` 1094 ```
965 1095
966 `GetxService`를 실질적으로 지우는 한가지 방법은 앱의 "Hot Reboot"과 같은 `Get.reset()`뿐 입니다. 1096 `GetxService`를 실질적으로 지우는 한가지 방법은 앱의 "Hot Reboot"과 같은 `Get.reset()`뿐 입니다.
967 -따라서 앱 실행중 절대로 유지되어야 하는 클래스 인스턴스가 필요하면 `GetxService`를 사용하세요. 1097 +따라서 앱 실행중 절대로 유지되어야 하는 클래스 인스턴스가 필요하면
  1098 +`GetxService`를 사용하세요.
968 1099
969 # 2.0의 주요 변경점 1100 # 2.0의 주요 변경점
970 1101
@@ -1056,6 +1187,7 @@ _프로젝트에 기여하고 싶으신가요? 우리는 귀하를 우리의 협 @@ -1056,6 +1187,7 @@ _프로젝트에 기여하고 싶으신가요? 우리는 귀하를 우리의 협
1056 1187
1057 ## 기사 및 비디오 1188 ## 기사 및 비디오
1058 1189
  1190 +- [Flutter Getx EcoSystem package for arabic people](https://www.youtube.com/playlist?list=PLV1fXIAyjeuZ6M8m56zajMUwu4uE3-SL0) - Tutorial by [Pesa Coder](https://github.com/UsamaElgendy).
1059 - [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr). 1191 - [Dynamic Themes in 3 lines using GetX™](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).
1060 - [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder. 1192 - [Complete GetX™ Navigation](https://www.youtube.com/watch?v=RaqPIoJSTtI) - Route management video by Amateur Coder.
1061 - [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder. 1193 - [Complete GetX State Management](https://www.youtube.com/watch?v=CNpXbeI_slw) - State management video by Amateur Coder.
@@ -1069,4 +1201,4 @@ _프로젝트에 기여하고 싶으신가요? 우리는 귀하를 우리의 협 @@ -1069,4 +1201,4 @@ _프로젝트에 기여하고 싶으신가요? 우리는 귀하를 우리의 협
1069 - [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris. 1201 - [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.
1070 - [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter. 1202 - [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
1071 - [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter. 1203 - [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
1072 - 1204 +- [A minimal example on dartpad](https://dartpad.dev/2b3d0d6f9d4e312c5fdbefc414c1727e?) - by [Roi Peker](https://github.com/roipeker)
@@ -6,12 +6,13 @@ @@ -6,12 +6,13 @@
6 - [Get.putAsync](#getputasync) 6 - [Get.putAsync](#getputasync)
7 - [Get.create](#getcreate) 7 - [Get.create](#getcreate)
8 - [Using instantiated methods/classes](#using-instantiated-methodsclasses) 8 - [Using instantiated methods/classes](#using-instantiated-methodsclasses)
  9 + - [Specifying an alternate instance](#specifying-an-alternate-instance)
9 - [Differences between methods](#differences-between-methods) 10 - [Differences between methods](#differences-between-methods)
10 - [Bindings](#bindings) 11 - [Bindings](#bindings)
11 - - [How to use](#how-to-use) 12 + - [Bindings class](#bindings-class)
12 - [BindingsBuilder](#bindingsbuilder) 13 - [BindingsBuilder](#bindingsbuilder)
13 - [SmartManagement](#smartmanagement) 14 - [SmartManagement](#smartmanagement)
14 - - [How to change](#How-to-change) 15 + - [How to change](#how-to-change)
15 - [SmartManagement.full](#smartmanagementfull) 16 - [SmartManagement.full](#smartmanagementfull)
16 - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders) 17 - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)
17 - [SmartManagement.keepFactory](#smartmanagementkeepfactory) 18 - [SmartManagement.keepFactory](#smartmanagementkeepfactory)
@@ -202,6 +203,25 @@ To remove an instance of Get: @@ -202,6 +203,25 @@ To remove an instance of Get:
202 Get.delete<Controller>(); //usually you don't need to do this because GetX already delete unused controllers 203 Get.delete<Controller>(); //usually you don't need to do this because GetX already delete unused controllers
203 ``` 204 ```
204 205
  206 +## Specifying an alternate instance
  207 +
  208 +A currently inserted instance can be replaced with a similar or extended class instance by using the `replace` method. This can then be retrieved by using the original class.
  209 +
  210 +```dart
  211 +class ParentClass {}
  212 +
  213 +class ChildClass extends ParentClass {
  214 + bool isChild = true;
  215 +}
  216 +
  217 +Get.put(ParentClass());
  218 +
  219 +Get.replace<ParentClass, ChildClass>(ChildClass());
  220 +
  221 +final instance = Get.find<ParentClass>();
  222 +print(instance is ChildClass); //true
  223 +```
  224 +
205 ## Differences between methods 225 ## Differences between methods
206 226
207 First, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods. 227 First, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods.
@@ -272,7 +272,7 @@ And now, all you need to do is use Get.toNamed() to navigate your named routes, @@ -272,7 +272,7 @@ And now, all you need to do is use Get.toNamed() to navigate your named routes,
272 272
273 ### Middleware 273 ### Middleware
274 274
275 -If you want listen Get events to trigger actions, you can to use routingCallback to it 275 +If you want to listen Get events to trigger actions, you can to use routingCallback to it
276 276
277 ```dart 277 ```dart
278 GetMaterialApp( 278 GetMaterialApp(
@@ -15,11 +15,11 @@ class MyApp extends StatelessWidget { @@ -15,11 +15,11 @@ class MyApp extends StatelessWidget {
15 15
16 @override 16 @override
17 Widget build(BuildContext context) { 17 Widget build(BuildContext context) {
18 - return GetMaterialApp( 18 + return GetMaterialApp.router(
19 debugShowCheckedModeBanner: false, 19 debugShowCheckedModeBanner: false,
20 enableLog: true, 20 enableLog: true,
21 logWriterCallback: Logger.write, 21 logWriterCallback: Logger.write,
22 - initialRoute: AppPages.INITIAL, 22 + // initialRoute: AppPages.INITIAL,
23 getPages: AppPages.routes, 23 getPages: AppPages.routes,
24 locale: TranslationService.locale, 24 locale: TranslationService.locale,
25 fallbackLocale: TranslationService.fallbackLocale, 25 fallbackLocale: TranslationService.fallbackLocale,
@@ -28,33 +28,37 @@ class MyApp extends StatelessWidget { @@ -28,33 +28,37 @@ class MyApp extends StatelessWidget {
28 } 28 }
29 } 29 }
30 30
31 -// Navigator 2 example, WIP  
32 -// TODO: add all methods from NavigatorExtension to GetNav 31 +/// Nav 2 snippet
  32 +// void main() {
  33 +// runApp(MyApp());
  34 +// }
33 35
34 // class MyApp extends StatelessWidget { 36 // class MyApp extends StatelessWidget {
35 // MyApp({Key? key}) : super(key: key); 37 // MyApp({Key? key}) : super(key: key);
36 38
37 -// final getNav = Get.put(  
38 -// GetNav(pages: [  
39 -// GetPage(name: '/first', page: () => First()),  
40 -// GetPage(name: '/second', page: () => Second()),  
41 -// GetPage(name: '/third', page: () => Third()),  
42 -// ]),  
43 -// );  
44 -  
45 // @override 39 // @override
46 // Widget build(BuildContext context) { 40 // Widget build(BuildContext context) {
47 // return GetMaterialApp.router( 41 // return GetMaterialApp.router(
  42 +// getPages: [
  43 +// GetPage(
  44 +// participatesInRootNavigator: true,
  45 +// name: '/first',
  46 +// page: () => First()),
  47 +// GetPage(
  48 +// name: '/second',
  49 +// page: () => Second(),
  50 +// ),
  51 +// GetPage(
  52 +// name: '/third',
  53 +// page: () => Third(),
  54 +// ),
  55 +// ],
48 // debugShowCheckedModeBanner: false, 56 // debugShowCheckedModeBanner: false,
49 -// routeInformationParser: getNav.routeInformationParser,  
50 -// routerDelegate: getNav.routerDelegate,  
51 // ); 57 // );
52 // } 58 // }
53 // } 59 // }
54 60
55 // class First extends StatelessWidget { 61 // class First extends StatelessWidget {
56 -// final GetNav getNav = Get.find();  
57 -  
58 // @override 62 // @override
59 // Widget build(BuildContext context) { 63 // Widget build(BuildContext context) {
60 // return Scaffold( 64 // return Scaffold(
@@ -73,9 +77,7 @@ class MyApp extends StatelessWidget { @@ -73,9 +77,7 @@ class MyApp extends StatelessWidget {
73 // height: 300, 77 // height: 300,
74 // width: 300, 78 // width: 300,
75 // child: ElevatedButton( 79 // child: ElevatedButton(
76 -// onPressed: () {  
77 -// getNav.toNamed('/second?id=584305');  
78 -// }, 80 +// onPressed: () {},
79 // child: Text('next screen'), 81 // child: Text('next screen'),
80 // ), 82 // ),
81 // ), 83 // ),
@@ -85,7 +87,6 @@ class MyApp extends StatelessWidget { @@ -85,7 +87,6 @@ class MyApp extends StatelessWidget {
85 // } 87 // }
86 88
87 // class Second extends StatelessWidget { 89 // class Second extends StatelessWidget {
88 -// final GetNav getNav = Get.find();  
89 // @override 90 // @override
90 // Widget build(BuildContext context) { 91 // Widget build(BuildContext context) {
91 // return Scaffold( 92 // return Scaffold(
@@ -97,9 +98,7 @@ class MyApp extends StatelessWidget { @@ -97,9 +98,7 @@ class MyApp extends StatelessWidget {
97 // height: 300, 98 // height: 300,
98 // width: 300, 99 // width: 300,
99 // child: ElevatedButton( 100 // child: ElevatedButton(
100 -// onPressed: () {  
101 -// getNav.toNamed('/third');  
102 -// }, 101 +// onPressed: () {},
103 // child: Text('next screen'), 102 // child: Text('next screen'),
104 // ), 103 // ),
105 // ), 104 // ),
@@ -109,7 +108,6 @@ class MyApp extends StatelessWidget { @@ -109,7 +108,6 @@ class MyApp extends StatelessWidget {
109 // } 108 // }
110 109
111 // class Third extends StatelessWidget { 110 // class Third extends StatelessWidget {
112 -// final GetNav getNav = Get.find();  
113 // @override 111 // @override
114 // Widget build(BuildContext context) { 112 // Widget build(BuildContext context) {
115 // return Scaffold( 113 // return Scaffold(
@@ -122,9 +120,7 @@ class MyApp extends StatelessWidget { @@ -122,9 +120,7 @@ class MyApp extends StatelessWidget {
122 // height: 300, 120 // height: 300,
123 // width: 300, 121 // width: 300,
124 // child: ElevatedButton( 122 // child: ElevatedButton(
125 -// onPressed: () {  
126 -// getNav.offUntil('/first');  
127 -// }, 123 +// onPressed: () {},
128 // child: Text('go to first screen'), 124 // child: Text('go to first screen'),
129 // ), 125 // ),
130 // ), 126 // ),
@@ -16,6 +16,15 @@ class HomeController extends SuperController<CasesModel> { @@ -16,6 +16,15 @@ class HomeController extends SuperController<CasesModel> {
16 append(() => homeRepository.getCases); 16 append(() => homeRepository.getCases);
17 } 17 }
18 18
  19 + Country getCountryById(String id) {
  20 + final index = int.tryParse(id);
  21 + if (index != null) {
  22 + return state!.countries[index];
  23 + }
  24 +
  25 + return state!.countries.first;
  26 + }
  27 +
19 @override 28 @override
20 void onReady() { 29 void onReady() {
21 print('The build method is done. ' 30 print('The build method is done. '
@@ -33,8 +33,9 @@ class CountryView extends GetView<HomeController> { @@ -33,8 +33,9 @@ class CountryView extends GetView<HomeController> {
33 final country = controller.state!.countries[index]; 33 final country = controller.state!.countries[index];
34 return ListTile( 34 return ListTile(
35 onTap: () { 35 onTap: () {
36 - Get.toNamed('/home/country/details',  
37 - arguments: country); 36 + //Get.rootDelegate.toNamed('/home/country');
  37 + Get.rootDelegate
  38 + .offNamed('/home/country/details?id=$index');
38 }, 39 },
39 trailing: CircleAvatar( 40 trailing: CircleAvatar(
40 backgroundImage: NetworkImage( 41 backgroundImage: NetworkImage(
@@ -2,13 +2,13 @@ import 'dart:ui'; @@ -2,13 +2,13 @@ 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 +import '../controllers/home_controller.dart';
5 6
6 -import '../../domain/entity/cases_model.dart';  
7 -  
8 -class DetailsView extends StatelessWidget { 7 +class DetailsView extends GetView<HomeController> {
9 @override 8 @override
10 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
11 - final country = Get.arguments as Country; 10 + final parameter = Get.rootDelegate.parameters;
  11 + final country = controller.getCountryById(parameter['id'] ?? '');
12 return Container( 12 return Container(
13 decoration: BoxDecoration( 13 decoration: BoxDecoration(
14 image: DecorationImage( 14 image: DecorationImage(
@@ -71,7 +71,7 @@ class HomeView extends GetView<HomeController> { @@ -71,7 +71,7 @@ class HomeView extends GetView<HomeController> {
71 shape: StadiumBorder(), 71 shape: StadiumBorder(),
72 ), 72 ),
73 onPressed: () { 73 onPressed: () {
74 - Get.toNamed('/home/country'); 74 + Get.rootDelegate.toNamed('/home/country');
75 }, 75 },
76 child: Text( 76 child: Text(
77 'fetch_country'.tr, 77 'fetch_country'.tr,
@@ -80,6 +80,26 @@ class HomeView extends GetView<HomeController> { @@ -80,6 +80,26 @@ class HomeView extends GetView<HomeController> {
80 color: Colors.black, 80 color: Colors.black,
81 ), 81 ),
82 ), 82 ),
  83 + ),
  84 + OutlinedButton(
  85 + style: OutlinedButton.styleFrom(
  86 + textStyle: TextStyle(color: Colors.black),
  87 + side: BorderSide(
  88 + color: Colors.deepPurple,
  89 + width: 3,
  90 + ),
  91 + shape: StadiumBorder(),
  92 + ),
  93 + onPressed: () {
  94 + Get.updateLocale(Locale('pt', 'BR'));
  95 + },
  96 + child: Text(
  97 + 'Update language to Portuguese',
  98 + style: TextStyle(
  99 + fontWeight: FontWeight.bold,
  100 + color: Colors.black,
  101 + ),
  102 + ),
83 ) 103 )
84 ], 104 ],
85 ); 105 );
  1 +import 'package:get/get.dart';
  2 +
  3 +import '../../services/auth_service.dart';
  4 +import '../routes/app_pages.dart';
  5 +
  6 +class EnsureAuthMiddleware extends GetMiddleware {
  7 + @override
  8 + Future<GetNavConfig?> redirectDelegate(GetNavConfig route) async {
  9 + // you can do whatever you want here
  10 + // but it's preferable to make this method fast
  11 + // await Future.delayed(Duration(milliseconds: 500));
  12 +
  13 + if (!AuthService.to.isLoggedInValue) {
  14 + final newRoute = Routes.LOGIN_THEN(route.location!);
  15 + return GetNavConfig.fromRoute(newRoute);
  16 + }
  17 + return await super.redirectDelegate(route);
  18 + }
  19 +}
  20 +
  21 +class EnsureNotAuthedMiddleware extends GetMiddleware {
  22 + @override
  23 + Future<GetNavConfig?> redirectDelegate(GetNavConfig route) async {
  24 + if (AuthService.to.isLoggedInValue) {
  25 + //NEVER navigate to auth screen, when user is already authed
  26 + return null;
  27 +
  28 + //OR redirect user to another screen
  29 + //return GetNavConfig.fromRoute(Routes.PROFILE);
  30 + }
  31 + return await super.redirectDelegate(route);
  32 + }
  33 +}
  1 +import 'package:get/get.dart';
  2 +
  3 +import '../controllers/dashboard_controller.dart';
  4 +
  5 +class DashboardBinding extends Bindings {
  6 + @override
  7 + void dependencies() {
  8 + Get.lazyPut<DashboardController>(
  9 + () => DashboardController(),
  10 + );
  11 + }
  12 +}
  1 +import 'dart:async';
  2 +
  3 +import 'package:get/get.dart';
  4 +
  5 +class DashboardController extends GetxController {
  6 + final now = DateTime.now().obs;
  7 + @override
  8 + void onReady() {
  9 + super.onReady();
  10 + Timer.periodic(
  11 + Duration(seconds: 1),
  12 + (timer) {
  13 + now.value = DateTime.now();
  14 + },
  15 + );
  16 + }
  17 +}
1 import 'package: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 '../controllers/home_controller.dart'; 4 +import '../controllers/dashboard_controller.dart';
5 5
6 -class DashboardView extends GetView<HomeController> { 6 +
  7 +class DashboardView extends GetView<DashboardController> {
7 @override 8 @override
8 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
9 return Scaffold( 10 return Scaffold(
@@ -16,7 +17,7 @@ class DashboardView extends GetView<HomeController> { @@ -16,7 +17,7 @@ class DashboardView extends GetView<HomeController> {
16 'DashboardView is working', 17 'DashboardView is working',
17 style: TextStyle(fontSize: 20), 18 style: TextStyle(fontSize: 20),
18 ), 19 ),
19 - Text('Time: ${controller.now.value.toString()}') 20 + Text('Time: ${controller.now.value.toString()}'),
20 ], 21 ],
21 ), 22 ),
22 ), 23 ),
1 -import 'dart:async';  
2 -  
3 import 'package:get/get.dart'; 1 import 'package:get/get.dart';
4 2
5 -class HomeController extends GetxController {  
6 - final now = DateTime.now().obs;  
7 - @override  
8 - void onReady() {  
9 - super.onReady();  
10 - Timer.periodic(  
11 - Duration(seconds: 1),  
12 - (timer) {  
13 - now.value = DateTime.now();  
14 - },  
15 - );  
16 - }  
17 -} 3 +class HomeController extends GetxController {}
@@ -3,7 +3,6 @@ import 'package:get/get.dart'; @@ -3,7 +3,6 @@ import 'package:get/get.dart';
3 3
4 import '../../../routes/app_pages.dart'; 4 import '../../../routes/app_pages.dart';
5 import '../controllers/home_controller.dart'; 5 import '../controllers/home_controller.dart';
6 -import 'dashboard_view.dart';  
7 6
8 class HomeView extends GetView<HomeController> { 7 class HomeView extends GetView<HomeController> {
9 @override 8 @override
@@ -21,23 +20,16 @@ class HomeView extends GetView<HomeController> { @@ -21,23 +20,16 @@ class HomeView extends GetView<HomeController> {
21 } 20 }
22 return Scaffold( 21 return Scaffold(
23 body: GetRouterOutlet( 22 body: GetRouterOutlet(
24 - name: Routes.HOME,  
25 - emptyWidget: (delegate) => DashboardView(),  
26 - pickPages: (currentNavStack) {  
27 - print('Home RouterOutlet: $currentNavStack');  
28 -  
29 - // will take any route after home  
30 - final res =  
31 - currentNavStack.currentTreeBranch.pickAfterRoute(Routes.HOME);  
32 - return res;  
33 - }, 23 + initialRoute: Routes.DASHBOARD,
  24 + // anchorRoute: Routes.HOME,
  25 + key: Get.nestedKey(Routes.HOME),
34 ), 26 ),
35 bottomNavigationBar: BottomNavigationBar( 27 bottomNavigationBar: BottomNavigationBar(
36 currentIndex: currentIndex, 28 currentIndex: currentIndex,
37 onTap: (value) { 29 onTap: (value) {
38 switch (value) { 30 switch (value) {
39 case 0: 31 case 0:
40 - delegate.until(Routes.HOME); 32 + delegate.toNamed(Routes.HOME);
41 break; 33 break;
42 case 1: 34 case 1:
43 delegate.toNamed(Routes.PROFILE); 35 delegate.toNamed(Routes.PROFILE);
  1 +import 'package:get/get.dart';
  2 +
  3 +import '../controllers/login_controller.dart';
  4 +
  5 +class LoginBinding extends Bindings {
  6 + @override
  7 + void dependencies() {
  8 + Get.lazyPut<LoginController>(
  9 + () => LoginController(),
  10 + );
  11 + }
  12 +}
  1 +import 'package:get/get.dart';
  2 +
  3 +class LoginController extends GetxController {}
  1 +import 'package:flutter/material.dart';
  2 +import 'package:get/get.dart';
  3 +
  4 +import '../../../../services/auth_service.dart';
  5 +import '../../../routes/app_pages.dart';
  6 +import '../controllers/login_controller.dart';
  7 +
  8 +class LoginView extends GetView<LoginController> {
  9 + @override
  10 + Widget build(BuildContext context) {
  11 + return Scaffold(
  12 + body: Center(
  13 + child: Column(
  14 + mainAxisSize: MainAxisSize.min,
  15 + children: [
  16 + Obx(
  17 + () {
  18 + final isLoggedIn = AuthService.to.isLoggedInValue;
  19 + return Text(
  20 + 'You are currently:'
  21 + ' ${isLoggedIn ? "Logged In" : "Not Logged In"}'
  22 + "\nIt's impossible to enter this "
  23 + "route when you are logged in!",
  24 + );
  25 + },
  26 + ),
  27 + MaterialButton(
  28 + child: Text(
  29 + 'Do LOGIN !!',
  30 + style: TextStyle(color: Colors.blue, fontSize: 20),
  31 + ),
  32 + onPressed: () {
  33 + AuthService.to.login();
  34 + final thenTo = Get.rootDelegate.currentConfiguration!
  35 + .currentPage!.parameters?['then'];
  36 + Get.rootDelegate.offNamed(thenTo ?? Routes.HOME);
  37 + },
  38 + ),
  39 + ],
  40 + ),
  41 + ),
  42 + );
  43 + }
  44 +}
@@ -4,4 +4,15 @@ class ProductDetailsController extends GetxController { @@ -4,4 +4,15 @@ class ProductDetailsController extends GetxController {
4 final String productId; 4 final String productId;
5 5
6 ProductDetailsController(this.productId); 6 ProductDetailsController(this.productId);
  7 + @override
  8 + void onInit() {
  9 + super.onInit();
  10 + Get.log('ProductDetailsController created with id: $productId');
  11 + }
  12 +
  13 + @override
  14 + void onClose() {
  15 + Get.log('ProductDetailsController close with id: $productId');
  16 + super.onClose();
  17 + }
7 } 18 }
1 import 'package:get/get.dart'; 1 import 'package:get/get.dart';
2 2
3 -import '../../../models/demo_product.dart'; 3 +import '../../../../models/demo_product.dart';
4 4
5 class ProductsController extends GetxController { 5 class ProductsController extends GetxController {
6 final products = <DemoProduct>[].obs; 6 final products = <DemoProduct>[].obs;
@@ -12,26 +12,37 @@ class ProductsView extends GetView<ProductsController> { @@ -12,26 +12,37 @@ class ProductsView extends GetView<ProductsController> {
12 onPressed: controller.loadDemoProductsFromSomeWhere, 12 onPressed: controller.loadDemoProductsFromSomeWhere,
13 label: Text('Add'), 13 label: Text('Add'),
14 ), 14 ),
15 - body: Obx(  
16 - () => RefreshIndicator(  
17 - onRefresh: () async {  
18 - controller.products.clear();  
19 - controller.loadDemoProductsFromSomeWhere();  
20 - },  
21 - child: ListView.builder(  
22 - itemCount: controller.products.length,  
23 - itemBuilder: (context, index) {  
24 - final item = controller.products[index];  
25 - return ListTile(  
26 - onTap: () {  
27 - Get.getDelegate()?.toNamed(Routes.PRODUCT_DETAILS(item.id)); 15 + body: Column(
  16 + children: [
  17 + Hero(
  18 + tag: 'heroLogo',
  19 + child: const FlutterLogo(),
  20 + ),
  21 + Expanded(
  22 + child: Obx(
  23 + () => RefreshIndicator(
  24 + onRefresh: () async {
  25 + controller.products.clear();
  26 + controller.loadDemoProductsFromSomeWhere();
28 }, 27 },
29 - title: Text(item.name),  
30 - subtitle: Text(item.id),  
31 - );  
32 - }, 28 + child: ListView.builder(
  29 + itemCount: controller.products.length,
  30 + itemBuilder: (context, index) {
  31 + final item = controller.products[index];
  32 + return ListTile(
  33 + onTap: () {
  34 + Get.rootDelegate
  35 + .toNamed(Routes.PRODUCT_DETAILS(item.id));
  36 + },
  37 + title: Text(item.name),
  38 + subtitle: Text(item.id),
  39 + );
  40 + },
  41 + ),
  42 + ),
  43 + ),
33 ), 44 ),
34 - ), 45 + ],
35 ), 46 ),
36 ); 47 );
37 } 48 }
1 import 'package:get/get.dart'; 1 import 'package:get/get.dart';
2 2
3 -class ProfileController extends GetxController {  
4 - //TODO: Implement ProfileController  
5 -  
6 - final count = 0.obs;  
7 - @override  
8 - void onInit() {  
9 - super.onInit();  
10 - }  
11 -  
12 - @override  
13 - void onReady() {  
14 - super.onReady();  
15 - }  
16 -  
17 - @override  
18 - void onClose() {}  
19 - void increment() => count.value++;  
20 -} 3 +class ProfileController extends GetxController {}
1 -import 'package:flutter/material.dart';  
2 -  
3 -import 'package:get/get.dart';  
4 -  
5 -import '../controllers/profile_controller.dart';  
6 -  
7 -class ProfileView extends GetView<ProfileController> {  
8 - @override  
9 - Widget build(BuildContext context) {  
10 - return Scaffold(  
11 - body: Center(  
12 - child: Text(  
13 - 'ProfileView is working',  
14 - style: TextStyle(fontSize: 20),  
15 - ),  
16 - ),  
17 - );  
18 - }  
19 -} 1 +import 'package:flutter/material.dart';
  2 +import 'package:get/get.dart';
  3 +
  4 +import '../../../routes/app_pages.dart';
  5 +import '../controllers/profile_controller.dart';
  6 +
  7 +class ProfileView extends GetView<ProfileController> {
  8 + @override
  9 + Widget build(BuildContext context) {
  10 + return Scaffold(
  11 + backgroundColor: Colors.amber,
  12 + body: Center(
  13 + child: Column(
  14 + mainAxisSize: MainAxisSize.min,
  15 + children: [
  16 + Text(
  17 + 'ProfileView is working',
  18 + style: TextStyle(fontSize: 20),
  19 + ),
  20 + Hero(
  21 + tag: 'heroLogo',
  22 + child: const FlutterLogo(),
  23 + ),
  24 + MaterialButton(
  25 + child: Text('Show a test dialog'),
  26 + onPressed: () {
  27 + //shows a dialog
  28 + Get.defaultDialog(
  29 + title: 'Test Dialog !!',
  30 + barrierDismissible: true,
  31 + );
  32 + },
  33 + ),
  34 + MaterialButton(
  35 + child: Text('Show a test dialog in Home router outlet'),
  36 + onPressed: () {
  37 + //shows a dialog
  38 +
  39 + Get.defaultDialog(
  40 + title: 'Test Dialog In Home Outlet !!',
  41 + barrierDismissible: true,
  42 + navigatorKey: Get.nestedKey(Routes.HOME),
  43 + );
  44 + },
  45 + )
  46 + ],
  47 + ),
  48 + ),
  49 + );
  50 + }
  51 +}
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 '../../../../services/auth_service.dart';
4 import '../../../routes/app_pages.dart'; 5 import '../../../routes/app_pages.dart';
5 6
6 class DrawerWidget extends StatelessWidget { 7 class DrawerWidget extends StatelessWidget {
@@ -20,7 +21,7 @@ class DrawerWidget extends StatelessWidget { @@ -20,7 +21,7 @@ class DrawerWidget extends StatelessWidget {
20 ListTile( 21 ListTile(
21 title: Text('Home'), 22 title: Text('Home'),
22 onTap: () { 23 onTap: () {
23 - Get.getDelegate()?.toNamed(Routes.HOME); 24 + Get.rootDelegate.toNamed(Routes.HOME);
24 //to close the drawer 25 //to close the drawer
25 26
26 Navigator.of(context).pop(); 27 Navigator.of(context).pop();
@@ -29,12 +30,43 @@ class DrawerWidget extends StatelessWidget { @@ -29,12 +30,43 @@ class DrawerWidget extends StatelessWidget {
29 ListTile( 30 ListTile(
30 title: Text('Settings'), 31 title: Text('Settings'),
31 onTap: () { 32 onTap: () {
32 - Get.getDelegate()?.toNamed(Routes.SETTINGS); 33 + Get.rootDelegate.toNamed(Routes.SETTINGS);
33 //to close the drawer 34 //to close the drawer
34 35
35 Navigator.of(context).pop(); 36 Navigator.of(context).pop();
36 }, 37 },
37 ), 38 ),
  39 + if (AuthService.to.isLoggedInValue)
  40 + ListTile(
  41 + title: Text(
  42 + 'Logout',
  43 + style: TextStyle(
  44 + color: Colors.red,
  45 + ),
  46 + ),
  47 + onTap: () {
  48 + AuthService.to.logout();
  49 + Get.rootDelegate.toNamed(Routes.LOGIN);
  50 + //to close the drawer
  51 +
  52 + Navigator.of(context).pop();
  53 + },
  54 + ),
  55 + if (!AuthService.to.isLoggedInValue)
  56 + ListTile(
  57 + title: Text(
  58 + 'Login',
  59 + style: TextStyle(
  60 + color: Colors.blue,
  61 + ),
  62 + ),
  63 + onTap: () {
  64 + Get.rootDelegate.toNamed(Routes.LOGIN);
  65 + //to close the drawer
  66 +
  67 + Navigator.of(context).pop();
  68 + },
  69 + ),
38 ], 70 ],
39 ), 71 ),
40 ); 72 );
@@ -9,8 +9,8 @@ class RootView extends GetView<RootController> { @@ -9,8 +9,8 @@ class RootView extends GetView<RootController> {
9 @override 9 @override
10 Widget build(BuildContext context) { 10 Widget build(BuildContext context) {
11 return GetRouterOutlet.builder( 11 return GetRouterOutlet.builder(
12 - builder: (context, rDelegate, currentRoute) {  
13 - final title = currentRoute?.location; 12 + builder: (context, delegate, current) {
  13 + final title = current?.location;
14 return Scaffold( 14 return Scaffold(
15 drawer: DrawerWidget(), 15 drawer: DrawerWidget(),
16 appBar: AppBar( 16 appBar: AppBar(
@@ -18,14 +18,11 @@ class RootView extends GetView<RootController> { @@ -18,14 +18,11 @@ class RootView extends GetView<RootController> {
18 centerTitle: true, 18 centerTitle: true,
19 ), 19 ),
20 body: GetRouterOutlet( 20 body: GetRouterOutlet(
21 - name: '/',  
22 - emptyPage: (delegate) =>  
23 - Get.routeTree.matchRoute(Routes.HOME).route!,  
24 - pickPages: (currentNavStack) {  
25 - //show all routes here except the root view  
26 - print('Root RouterOutlet: $currentNavStack');  
27 - return currentNavStack.currentTreeBranch.skip(1).take(1).toList();  
28 - }, 21 + initialRoute: Routes.HOME,
  22 + // anchorRoute: '/',
  23 + // filterPages: (afterAnchor) {
  24 + // return afterAnchor.take(1);
  25 + // },
29 ), 26 ),
30 ); 27 );
31 }, 28 },
1 import 'package:get/get.dart'; 1 import 'package:get/get.dart';
2 -import 'package:get/get_navigation/src/nav2/router_outlet.dart';  
3 2
  3 +import '../middleware/auth_middleware.dart';
  4 +import '../modules/dashboard/bindings/dashboard_binding.dart';
  5 +import '../modules/dashboard/views/dashboard_view.dart';
4 import '../modules/home/bindings/home_binding.dart'; 6 import '../modules/home/bindings/home_binding.dart';
5 import '../modules/home/views/home_view.dart'; 7 import '../modules/home/views/home_view.dart';
  8 +import '../modules/login/bindings/login_binding.dart';
  9 +import '../modules/login/views/login_view.dart';
6 import '../modules/product_details/bindings/product_details_binding.dart'; 10 import '../modules/product_details/bindings/product_details_binding.dart';
7 import '../modules/product_details/views/product_details_view.dart'; 11 import '../modules/product_details/views/product_details_view.dart';
8 import '../modules/products/bindings/products_binding.dart'; 12 import '../modules/products/bindings/products_binding.dart';
@@ -25,14 +29,22 @@ class AppPages { @@ -25,14 +29,22 @@ class AppPages {
25 GetPage( 29 GetPage(
26 name: '/', 30 name: '/',
27 page: () => RootView(), 31 page: () => RootView(),
28 - middlewares: [  
29 - RouterOutletContainerMiddleWare('/'),  
30 - ],  
31 binding: RootBinding(), 32 binding: RootBinding(),
  33 + participatesInRootNavigator: true,
  34 + preventDuplicates: true,
32 children: [ 35 children: [
33 GetPage( 36 GetPage(
34 - name: _Paths.HOME, 37 + middlewares: [
  38 + //only enter this route when not authed
  39 + EnsureNotAuthedMiddleware(),
  40 + ],
  41 + name: _Paths.LOGIN,
  42 + page: () => LoginView(),
  43 + binding: LoginBinding(),
  44 + ),
  45 + GetPage(
35 preventDuplicates: true, 46 preventDuplicates: true,
  47 + name: _Paths.HOME,
36 page: () => HomeView(), 48 page: () => HomeView(),
37 bindings: [ 49 bindings: [
38 HomeBinding(), 50 HomeBinding(),
@@ -40,6 +52,15 @@ class AppPages { @@ -40,6 +52,15 @@ class AppPages {
40 title: null, 52 title: null,
41 children: [ 53 children: [
42 GetPage( 54 GetPage(
  55 + name: _Paths.DASHBOARD,
  56 + page: () => DashboardView(),
  57 + binding: DashboardBinding(),
  58 + ),
  59 + GetPage(
  60 + middlewares: [
  61 + //only enter this route when authed
  62 + EnsureAuthMiddleware(),
  63 + ],
43 name: _Paths.PROFILE, 64 name: _Paths.PROFILE,
44 page: () => ProfileView(), 65 page: () => ProfileView(),
45 title: 'Profile', 66 title: 'Profile',
@@ -57,6 +78,10 @@ class AppPages { @@ -57,6 +78,10 @@ class AppPages {
57 name: _Paths.PRODUCT_DETAILS, 78 name: _Paths.PRODUCT_DETAILS,
58 page: () => ProductDetailsView(), 79 page: () => ProductDetailsView(),
59 binding: ProductDetailsBinding(), 80 binding: ProductDetailsBinding(),
  81 + middlewares: [
  82 + //only enter this route when authed
  83 + EnsureAuthMiddleware(),
  84 + ],
60 ), 85 ),
61 ], 86 ],
62 ), 87 ),
@@ -11,6 +11,10 @@ abstract class Routes { @@ -11,6 +11,10 @@ abstract class Routes {
11 11
12 static const PRODUCTS = _Paths.HOME + _Paths.PRODUCTS; 12 static const PRODUCTS = _Paths.HOME + _Paths.PRODUCTS;
13 static String PRODUCT_DETAILS(String productId) => '$PRODUCTS/$productId'; 13 static String PRODUCT_DETAILS(String productId) => '$PRODUCTS/$productId';
  14 + static const LOGIN = _Paths.LOGIN;
  15 + static String LOGIN_THEN(String afterSuccessfulLogin) =>
  16 + '$LOGIN?then=${Uri.encodeQueryComponent(afterSuccessfulLogin)}';
  17 + static const DASHBOARD = _Paths.HOME + _Paths.DASHBOARD;
14 } 18 }
15 19
16 abstract class _Paths { 20 abstract class _Paths {
@@ -19,4 +23,6 @@ abstract class _Paths { @@ -19,4 +23,6 @@ abstract class _Paths {
19 static const PROFILE = '/profile'; 23 static const PROFILE = '/profile';
20 static const SETTINGS = '/settings'; 24 static const SETTINGS = '/settings';
21 static const PRODUCT_DETAILS = '/:productId'; 25 static const PRODUCT_DETAILS = '/:productId';
  26 + static const LOGIN = '/login';
  27 + static const DASHBOARD = '/dashboard';
22 } 28 }
1 -import 'package:flutter/material.dart';  
2 -  
3 -import 'package:get/get.dart';  
4 -import 'package:get/get_navigation/src/nav2/get_router_delegate.dart';  
5 -  
6 -import 'app/routes/app_pages.dart';  
7 -  
8 -void main() {  
9 - runApp(  
10 - GetMaterialApp.router(  
11 - title: "Application",  
12 - getPages: AppPages.routes,  
13 - routeInformationParser: GetInformationParser(  
14 - // initialRoute: Routes.HOME,  
15 - ),  
16 - routerDelegate: GetDelegate(  
17 - backButtonPopMode: PopMode.History,  
18 - preventDuplicateHandlingMode:  
19 - PreventDuplicateHandlingMode.PopUntilOriginalRoute,  
20 - ),  
21 - ),  
22 - );  
23 -} 1 +import 'package:flutter/material.dart';
  2 +import 'package:get/get.dart';
  3 +
  4 +import 'app/routes/app_pages.dart';
  5 +import 'services/auth_service.dart';
  6 +
  7 +void main() {
  8 + runApp(
  9 + GetMaterialApp.router(
  10 + title: "Application",
  11 + initialBinding: BindingsBuilder(
  12 + () {
  13 + Get.put(AuthService());
  14 + },
  15 + ),
  16 + getPages: AppPages.routes,
  17 + // routeInformationParser: GetInformationParser(
  18 + // // initialRoute: Routes.HOME,
  19 + // ),
  20 + // routerDelegate: GetDelegate(
  21 + // backButtonPopMode: PopMode.History,
  22 + // preventDuplicateHandlingMode:
  23 + // PreventDuplicateHandlingMode.ReorderRoutes,
  24 + // ),
  25 + ),
  26 + );
  27 +}
1 -class DemoProduct {  
2 - final String name;  
3 - final String id;  
4 -  
5 - DemoProduct({  
6 - required this.name,  
7 - required this.id,  
8 - });  
9 -} 1 +class DemoProduct {
  2 + final String name;
  3 + final String id;
  4 +
  5 + DemoProduct({
  6 + required this.name,
  7 + required this.id,
  8 + });
  9 +}
  1 +import 'package:get/get.dart';
  2 +
  3 +class AuthService extends GetxService {
  4 + static AuthService get to => Get.find();
  5 +
  6 + /// Mocks a login process
  7 + final isLoggedIn = false.obs;
  8 + bool get isLoggedInValue => isLoggedIn.value;
  9 +
  10 + void login() {
  11 + isLoggedIn.value = true;
  12 + }
  13 +
  14 + void logout() {
  15 + isLoggedIn.value = false;
  16 + }
  17 +}
@@ -2,6 +2,8 @@ @@ -2,6 +2,8 @@
2 // Generated file. Do not edit. 2 // Generated file. Do not edit.
3 // 3 //
4 4
  5 +// clang-format off
  6 +
5 #include "generated_plugin_registrant.h" 7 #include "generated_plugin_registrant.h"
6 8
7 9
@@ -2,6 +2,8 @@ @@ -2,6 +2,8 @@
2 // Generated file. Do not edit. 2 // Generated file. Do not edit.
3 // 3 //
4 4
  5 +// clang-format off
  6 +
5 #ifndef GENERATED_PLUGIN_REGISTRANT_ 7 #ifndef GENERATED_PLUGIN_REGISTRANT_
6 #define GENERATED_PLUGIN_REGISTRANT_ 8 #define GENERATED_PLUGIN_REGISTRANT_
7 9
@@ -33,6 +33,7 @@ abstract class GetConnectInterface with GetLifeCycleBase { @@ -33,6 +33,7 @@ abstract class GetConnectInterface with GetLifeCycleBase {
33 Map<String, dynamic>? query, 33 Map<String, dynamic>? query,
34 Decoder<T>? decoder, 34 Decoder<T>? decoder,
35 }); 35 });
  36 +
36 Future<Response<T>> post<T>( 37 Future<Response<T>> post<T>(
37 String url, 38 String url,
38 dynamic body, { 39 dynamic body, {
@@ -95,6 +96,7 @@ class GetConnect extends GetConnectInterface { @@ -95,6 +96,7 @@ class GetConnect extends GetConnectInterface {
95 this.timeout = const Duration(seconds: 5), 96 this.timeout = const Duration(seconds: 5),
96 this.followRedirects = true, 97 this.followRedirects = true,
97 this.maxRedirects = 5, 98 this.maxRedirects = 5,
  99 + this.sendUserAgent = false,
98 this.maxAuthRetries = 1, 100 this.maxAuthRetries = 1,
99 this.allowAutoSignedCert = false, 101 this.allowAutoSignedCert = false,
100 this.withCredentials = false, 102 this.withCredentials = false,
@@ -104,6 +106,7 @@ class GetConnect extends GetConnectInterface { @@ -104,6 +106,7 @@ class GetConnect extends GetConnectInterface {
104 106
105 bool allowAutoSignedCert; 107 bool allowAutoSignedCert;
106 String userAgent; 108 String userAgent;
  109 + bool sendUserAgent;
107 String? baseUrl; 110 String? baseUrl;
108 String defaultContentType = 'application/json; charset=utf-8'; 111 String defaultContentType = 'application/json; charset=utf-8';
109 bool followRedirects; 112 bool followRedirects;
@@ -122,6 +125,7 @@ class GetConnect extends GetConnectInterface { @@ -122,6 +125,7 @@ class GetConnect extends GetConnectInterface {
122 @override 125 @override
123 GetHttpClient get httpClient => _httpClient ??= GetHttpClient( 126 GetHttpClient get httpClient => _httpClient ??= GetHttpClient(
124 userAgent: userAgent, 127 userAgent: userAgent,
  128 + sendUserAgent: sendUserAgent,
125 timeout: timeout, 129 timeout: timeout,
126 followRedirects: followRedirects, 130 followRedirects: followRedirects,
127 maxRedirects: maxRedirects, 131 maxRedirects: maxRedirects,
@@ -310,7 +314,6 @@ class GetConnect extends GetConnectInterface { @@ -310,7 +314,6 @@ class GetConnect extends GetConnectInterface {
310 314
311 final listError = res.body['errors']; 315 final listError = res.body['errors'];
312 if ((listError is List) && listError.isNotEmpty) { 316 if ((listError is List) && listError.isNotEmpty) {
313 - // return GraphQLResponse<T>(body: res.body['data'] as T);  
314 return GraphQLResponse<T>( 317 return GraphQLResponse<T>(
315 graphQLErrors: listError 318 graphQLErrors: listError
316 .map((e) => GraphQLError( 319 .map((e) => GraphQLError(
@@ -346,7 +349,6 @@ class GetConnect extends GetConnectInterface { @@ -346,7 +349,6 @@ class GetConnect extends GetConnectInterface {
346 349
347 final listError = res.body['errors']; 350 final listError = res.body['errors'];
348 if ((listError is List) && listError.isNotEmpty) { 351 if ((listError is List) && listError.isNotEmpty) {
349 - // return GraphQLResponse<T>(body: res.body['data'] as T);  
350 return GraphQLResponse<T>( 352 return GraphQLResponse<T>(
351 graphQLErrors: listError 353 graphQLErrors: listError
352 .map((e) => GraphQLError( 354 .map((e) => GraphQLError(
@@ -27,6 +27,8 @@ class GetHttpClient { @@ -27,6 +27,8 @@ class GetHttpClient {
27 int maxRedirects; 27 int maxRedirects;
28 int maxAuthRetries; 28 int maxAuthRetries;
29 29
  30 + bool sendUserAgent;
  31 +
30 Decoder? defaultDecoder; 32 Decoder? defaultDecoder;
31 33
32 Duration timeout; 34 Duration timeout;
@@ -42,6 +44,7 @@ class GetHttpClient { @@ -42,6 +44,7 @@ class GetHttpClient {
42 this.timeout = const Duration(seconds: 8), 44 this.timeout = const Duration(seconds: 8),
43 this.followRedirects = true, 45 this.followRedirects = true,
44 this.maxRedirects = 5, 46 this.maxRedirects = 5,
  47 + this.sendUserAgent = false,
45 this.maxAuthRetries = 1, 48 this.maxAuthRetries = 1,
46 bool allowAutoSignedCert = false, 49 bool allowAutoSignedCert = false,
47 this.baseUrl, 50 this.baseUrl,
@@ -98,7 +101,9 @@ class GetHttpClient { @@ -98,7 +101,9 @@ class GetHttpClient {
98 Stream<List<int>>? bodyStream; 101 Stream<List<int>>? bodyStream;
99 final headers = <String, String>{}; 102 final headers = <String, String>{};
100 103
101 - headers['user-agent'] = userAgent; 104 + if (sendUserAgent) {
  105 + headers['user-agent'] = userAgent;
  106 + }
102 107
103 if (body is FormData) { 108 if (body is FormData) {
104 bodyBytes = await body.toBytes(); 109 bodyBytes = await body.toBytes();
@@ -179,7 +184,9 @@ class GetHttpClient { @@ -179,7 +184,9 @@ class GetHttpClient {
179 String? contentType, 184 String? contentType,
180 ) { 185 ) {
181 headers['content-type'] = contentType ?? defaultContentType; 186 headers['content-type'] = contentType ?? defaultContentType;
182 - headers['user-agent'] = userAgent; 187 + if (sendUserAgent) {
  188 + headers['user-agent'] = userAgent;
  189 + }
183 } 190 }
184 191
185 Future<Response<T>> _performRequest<T>( 192 Future<Response<T>> _performRequest<T>(
@@ -4,7 +4,7 @@ List<int> fileToBytes(dynamic data) { @@ -4,7 +4,7 @@ List<int> fileToBytes(dynamic data) {
4 if (data is List<int>) { 4 if (data is List<int>) {
5 return data; 5 return data;
6 } else { 6 } else {
7 - throw FormatException('File is not [File] or [String] or [List<int>]'); 7 + throw FormatException('File is not "File" or "String" or "List<int>"');
8 } 8 }
9 } 9 }
10 10
@@ -7,12 +7,12 @@ List<int> fileToBytes(dynamic data) { @@ -7,12 +7,12 @@ List<int> fileToBytes(dynamic data) {
7 if (File(data).existsSync()) { 7 if (File(data).existsSync()) {
8 return File(data).readAsBytesSync(); 8 return File(data).readAsBytesSync();
9 } else { 9 } else {
10 - throw 'File [data] not exists'; 10 + throw 'File $data not exists';
11 } 11 }
12 } else if (data is List<int>) { 12 } else if (data is List<int>) {
13 return data; 13 return data;
14 } else { 14 } else {
15 - throw FormatException('File is not [File] or [String] or [List<int>]'); 15 + throw FormatException('File is not "File" or "String" or "List<int>"');
16 } 16 }
17 } 17 }
18 18
@@ -34,7 +34,6 @@ class HttpRequestImpl extends HttpRequestBase { @@ -34,7 +34,6 @@ class HttpRequestImpl extends HttpRequestBase {
34 @override 34 @override
35 Future<Response<T>> send<T>(Request<T> request) async { 35 Future<Response<T>> send<T>(Request<T> request) async {
36 var stream = request.bodyBytes.asBroadcastStream(); 36 var stream = request.bodyBytes.asBroadcastStream();
37 - //var stream = BodyBytesStream.fromBytes(requestBody ?? const []);  
38 37
39 try { 38 try {
40 var ioRequest = (await _httpClient!.openUrl(request.method, request.url)) 39 var ioRequest = (await _httpClient!.openUrl(request.method, request.url))
@@ -36,7 +36,7 @@ class FormData { @@ -36,7 +36,7 @@ class FormData {
36 /// The form fields to send for this request. 36 /// The form fields to send for this request.
37 final fields = <MapEntry<String, String>>[]; 37 final fields = <MapEntry<String, String>>[];
38 38
39 - /// The [files] to send for this request 39 + /// The files to send for this request
40 final files = <MapEntry<String, MultipartFile>>[]; 40 final files = <MapEntry<String, MultipartFile>>[];
41 41
42 /// Returns the header string for a field. The return value is guaranteed to 42 /// Returns the header string for a field. The return value is guaranteed to
@@ -66,7 +66,7 @@ class Response<T> { @@ -66,7 +66,7 @@ class Response<T> {
66 66
67 /// The decoded body of this [Response]. You can access the 67 /// The decoded body of this [Response]. You can access the
68 /// body parameters as Map 68 /// body parameters as Map
69 - /// Ex: body['title']; 69 + /// Ex: `body['title'];`
70 final T? body; 70 final T? body;
71 } 71 }
72 72
@@ -91,7 +91,7 @@ Encoding _encodingForCharset(String? charset, [Encoding fallback = utf8]) { @@ -91,7 +91,7 @@ Encoding _encodingForCharset(String? charset, [Encoding fallback = utf8]) {
91 return Encoding.getByName(charset) ?? fallback; 91 return Encoding.getByName(charset) ?? fallback;
92 } 92 }
93 93
94 -/// Returns the [MediaType] object for the given headers's content-type. 94 +/// Returns the MediaType object for the given headers's content-type.
95 /// 95 ///
96 /// Defaults to `application/octet-stream`. 96 /// Defaults to `application/octet-stream`.
97 HeaderValue _contentTypeForHeaders(Map<String, String> headers) { 97 HeaderValue _contentTypeForHeaders(Map<String, String> headers) {
@@ -8,6 +8,7 @@ import 'smart_management.dart'; @@ -8,6 +8,7 @@ import 'smart_management.dart';
8 abstract class GetInterface { 8 abstract class GetInterface {
9 SmartManagement smartManagement = SmartManagement.full; 9 SmartManagement smartManagement = SmartManagement.full;
10 RouterDelegate? routerDelegate; 10 RouterDelegate? routerDelegate;
  11 + RouteInformationParser? routeInformationParser;
11 String? reference; 12 String? reference;
12 bool isLogEnable = true; 13 bool isLogEnable = true;
13 LogWriterCallback log = defaultLogWriterCallback; 14 LogWriterCallback log = defaultLogWriterCallback;
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 /// not being used and were not set to be permanent. In the majority 5 /// not being used and were not set to be permanent. In the majority
6 /// of the cases you will want to keep this config untouched. 6 /// of the cases you will want to keep this config untouched.
7 /// If you new to GetX then don't change this. 7 /// If you new to GetX then don't change this.
8 -/// [SmartManagement.onlyBuilders] only controllers started in init: 8 +/// [SmartManagement.onlyBuilder] only controllers started in init:
9 /// or loaded into a Binding with Get.lazyPut() will be disposed. If you use 9 /// or loaded into a Binding with Get.lazyPut() will be disposed. If you use
10 /// Get.put() or Get.putAsync() or any other approach, SmartManagement 10 /// Get.put() or Get.putAsync() or any other approach, SmartManagement
11 /// will not have permissions to exclude this dependency. With the default 11 /// will not have permissions to exclude this dependency. With the default
1 import 'get_instance.dart'; 1 import 'get_instance.dart';
2 2
3 /// [Bindings] should be extended or implemented. 3 /// [Bindings] should be extended or implemented.
4 -/// When using [GetMaterialApp], all [GetPage]s and navigation  
5 -/// methods (like Get.to()) have a [binding] property that takes an 4 +/// When using `GetMaterialApp`, all `GetPage`s and navigation
  5 +/// methods (like Get.to()) have a `binding` property that takes an
6 /// instance of Bindings to manage the 6 /// instance of Bindings to manage the
7 -/// dependencies() (via [Get.put()]) for the Route you are opening. 7 +/// dependencies() (via Get.put()) for the Route you are opening.
8 // ignore: one_member_abstracts 8 // ignore: one_member_abstracts
9 abstract class Bindings { 9 abstract class Bindings {
10 void dependencies(); 10 void dependencies();
@@ -3,30 +3,30 @@ import '../../route_manager.dart'; @@ -3,30 +3,30 @@ import '../../route_manager.dart';
3 import 'get_instance.dart'; 3 import 'get_instance.dart';
4 4
5 extension Inst on GetInterface { 5 extension Inst on GetInterface {
6 - /// Creates a new Instance<S> lazily from the [<S>builder()] callback. 6 + /// Creates a new Instance<S> lazily from the `<S>builder()` callback.
7 /// 7 ///
8 - /// The first time you call [Get.find()], the [builder()] callback will create 8 + /// The first time you call `Get.find()`, the `builder()` callback will create
9 /// the Instance and persisted as a Singleton (like you would use 9 /// the Instance and persisted as a Singleton (like you would use
10 - /// [Get.put()]). 10 + /// `Get.put()`).
11 /// 11 ///
12 - /// Using [Get.smartManagement] as [SmartManagement.keepFactory] has 12 + /// Using `Get.smartManagement` as [SmartManagement.keepFactory] has
13 /// the same outcome 13 /// the same outcome
14 - /// as using [fenix:true] :  
15 - /// The internal register of [builder()] will remain in memory to recreate  
16 - /// the Instance if the Instance has been removed with [Get.delete()].  
17 - /// Therefore, future calls to [Get.find()] will return the same Instance. 14 + /// as using `fenix:true` :
  15 + /// The internal register of `builder()` will remain in memory to recreate
  16 + /// the Instance if the Instance has been removed with `Get.delete()`.
  17 + /// Therefore, future calls to `Get.find()` will return the same Instance.
18 /// 18 ///
19 /// If you need to make use of GetxController's life-cycle 19 /// If you need to make use of GetxController's life-cycle
20 - /// ([onInit(), onStart(), onClose()])  
21 - /// [fenix] is a great choice to mix with [GetBuilder()] and [GetX()] widgets, 20 + /// (`onInit(), onStart(), onClose()`)
  21 + /// [fenix] is a great choice to mix with `GetBuilder` and `GetX` widgets,
22 /// and/or [GetMaterialApp] Navigation. 22 /// and/or [GetMaterialApp] Navigation.
23 /// 23 ///
24 - /// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead of  
25 - /// [Bindings()] for each [GetPage]. 24 + /// You could use `Get.lazyPut(fenix:true)` in your app's `main()` instead of
  25 + /// `Bindings` for each [GetPage].
26 /// And the memory management will be similar. 26 /// And the memory management will be similar.
27 /// 27 ///
28 - /// Subsequent calls to [Get.lazyPut()] with the same parameters  
29 - /// (<[S]> and optionally [tag] will **not** override the original). 28 + /// Subsequent calls to `Get.lazyPut` with the same parameters
  29 + /// (`<S>` and optionally [tag] will **not** override the original).
30 void lazyPut<S>(InstanceBuilderCallback<S> builder, 30 void lazyPut<S>(InstanceBuilderCallback<S> builder,
31 {String? tag, bool fenix = false}) { 31 {String? tag, bool fenix = false}) {
32 GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix); 32 GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix);
@@ -36,21 +36,21 @@ extension Inst on GetInterface { @@ -36,21 +36,21 @@ extension Inst on GetInterface {
36 GetInstance().printInstanceStack(); 36 GetInstance().printInstanceStack();
37 } 37 }
38 38
39 - /// async version of [Get.put()].  
40 - /// Awaits for the resolution of the Future from [builder()] parameter and 39 + /// async version of `Get.put()`.
  40 + /// Awaits for the resolution of the Future from `builder()`parameter and
41 /// stores the Instance returned. 41 /// stores the Instance returned.
42 Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder, 42 Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
43 {String? tag, bool permanent = false}) async => 43 {String? tag, bool permanent = false}) async =>
44 GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent); 44 GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
45 45
46 /// Creates a new Class Instance [S] from the builder callback[S]. 46 /// Creates a new Class Instance [S] from the builder callback[S].
47 - /// Every time [find]<[S]>() is used, it calls the builder method to generate 47 + /// Every time `find<S>()` is used, it calls the builder method to generate
48 /// a new Instance [S]. 48 /// a new Instance [S].
49 - /// It also registers each [instance.onClose()] with the current  
50 - /// Route [GetConfig.currentRoute] to keep the lifecycle active. 49 + /// It also registers each `instance.onClose()` with the current
  50 + /// Route `GetConfig.currentRoute` to keep the lifecycle active.
51 /// Is important to know that the instances created are only stored per Route. 51 /// Is important to know that the instances created are only stored per Route.
52 /// So, if you call `Get.delete<T>()` the "instance factory" used in this 52 /// So, if you call `Get.delete<T>()` the "instance factory" used in this
53 - /// method ([Get.create<T>()]) will be removed, but NOT the instances 53 + /// method (`Get.create<T>()`) will be removed, but NOT the instances
54 /// already created by it. 54 /// already created by it.
55 /// Uses `tag` as the other methods. 55 /// Uses `tag` as the other methods.
56 /// 56 ///
@@ -64,24 +64,24 @@ extension Inst on GetInterface { @@ -64,24 +64,24 @@ extension Inst on GetInterface {
64 {String? tag, bool permanent = true}) => 64 {String? tag, bool permanent = true}) =>
65 GetInstance().create<S>(builder, tag: tag, permanent: permanent); 65 GetInstance().create<S>(builder, tag: tag, permanent: permanent);
66 66
67 - /// Finds a Instance of the required Class <[S]>(or [tag])  
68 - /// In the case of using [Get.create()], it will generate an Instance  
69 - /// each time you call [Get.find()]. 67 + /// Finds a Instance of the required Class `<S>`(or [tag])
  68 + /// In the case of using `Get.create()`, it will generate an Instance
  69 + /// each time you call `Get.find()`.
70 S find<S>({String? tag}) => GetInstance().find<S>(tag: tag); 70 S find<S>({String? tag}) => GetInstance().find<S>(tag: tag);
71 71
72 - /// Injects an [Instance<S>] in memory. 72 + /// Injects an `Instance<S>` in memory.
73 /// 73 ///
74 - /// No need to define the generic type <[S]> as it's inferred 74 + /// No need to define the generic type `<[S]>` as it's inferred
75 /// from the [dependency] parameter. 75 /// from the [dependency] parameter.
76 /// 76 ///
77 /// - [dependency] The Instance to be injected. 77 /// - [dependency] The Instance to be injected.
78 /// - [tag] optionally, use a [tag] as an "id" to create multiple records 78 /// - [tag] optionally, use a [tag] as an "id" to create multiple records
79 - /// of the same Type<[S]> the [tag] does **not** conflict with the same tags  
80 - /// used by other [dependencies] Types. 79 + /// of the same `Type<S>` the [tag] does **not** conflict with the same tags
  80 + /// used by other dependencies Types.
81 /// - [permanent] keeps the Instance in memory and persist it, 81 /// - [permanent] keeps the Instance in memory and persist it,
82 - /// not following [Get.smartManagement]  
83 - /// rules. Although, can be removed by [GetInstance.reset()]  
84 - /// and [Get.delete()] 82 + /// not following `Get.smartManagement`
  83 + /// rules. Although, can be removed by `GetInstance.reset()`
  84 + /// and `Get.delete()`
85 /// - [builder] If defined, the [dependency] must be returned from here 85 /// - [builder] If defined, the [dependency] must be returned from here
86 S put<S>(S dependency, 86 S put<S>(S dependency,
87 {String? tag, 87 {String? tag,
@@ -92,25 +92,25 @@ extension Inst on GetInterface { @@ -92,25 +92,25 @@ extension Inst on GetInterface {
92 /// Clears all registered instances (and/or tags). 92 /// Clears all registered instances (and/or tags).
93 /// Even the persistent ones. 93 /// Even the persistent ones.
94 /// 94 ///
95 - /// - [clearFactory] clears the callbacks registered by [Get.lazyPut()] 95 + /// - [clearFactory] clears the callbacks registered by `Get.lazyPut()`
96 /// - [clearRouteBindings] clears Instances associated with Routes when using 96 /// - [clearRouteBindings] clears Instances associated with Routes when using
97 /// [GetMaterialApp]. 97 /// [GetMaterialApp].
98 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) => 98 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) =>
99 GetInstance().reset( 99 GetInstance().reset(
100 clearFactory: clearFactory, clearRouteBindings: clearRouteBindings); 100 clearFactory: clearFactory, clearRouteBindings: clearRouteBindings);
101 101
102 - /// Deletes the Instance<[S]>, cleaning the memory and closes any open  
103 - /// controllers ([DisposableInterface]). 102 + /// Deletes the `Instance<S>`, cleaning the memory and closes any open
  103 + /// controllers (`DisposableInterface`).
104 /// 104 ///
105 /// - [tag] Optional "tag" used to register the Instance 105 /// - [tag] Optional "tag" used to register the Instance
106 - /// - [force] Will delete an Instance even if marked as [permanent]. 106 + /// - [force] Will delete an Instance even if marked as `permanent`.
107 Future<bool> delete<S>({String? tag, bool force = false}) async => 107 Future<bool> delete<S>({String? tag, bool force = false}) async =>
108 GetInstance().delete<S>(tag: tag, force: force); 108 GetInstance().delete<S>(tag: tag, force: force);
109 109
110 /// Deletes all Instances, cleaning the memory and closes any open 110 /// Deletes all Instances, cleaning the memory and closes any open
111 - /// controllers ([DisposableInterface]). 111 + /// controllers (`DisposableInterface`).
112 /// 112 ///
113 - /// - [force] Will delete the Instances even if marked as [permanent]. 113 + /// - [force] Will delete the Instances even if marked as `permanent`.
114 Future<void> deleteAll({bool force = false}) async => 114 Future<void> deleteAll({bool force = false}) async =>
115 GetInstance().deleteAll(force: force); 115 GetInstance().deleteAll(force: force);
116 116
@@ -119,13 +119,38 @@ extension Inst on GetInterface { @@ -119,13 +119,38 @@ extension Inst on GetInterface {
119 void reload<S>({String? tag, String? key, bool force = false}) => 119 void reload<S>({String? tag, String? key, bool force = false}) =>
120 GetInstance().reload<S>(tag: tag, key: key, force: force); 120 GetInstance().reload<S>(tag: tag, key: key, force: force);
121 121
122 - /// Checks if a Class Instance<[S]> (or [tag]) is registered in memory. 122 + /// Checks if a Class `Instance<S>` (or [tag]) is registered in memory.
123 /// - [tag] optional, if you use a [tag] to register the Instance. 123 /// - [tag] optional, if you use a [tag] to register the Instance.
124 bool isRegistered<S>({String? tag}) => 124 bool isRegistered<S>({String? tag}) =>
125 GetInstance().isRegistered<S>(tag: tag); 125 GetInstance().isRegistered<S>(tag: tag);
126 126
127 - /// Checks if an Instance<[S]> (or [tag]) returned from a factory builder  
128 - /// [Get.lazyPut()], is registered in memory. 127 + /// Checks if an `Instance<S>` (or [tag]) returned from a factory builder
  128 + /// `Get.lazyPut()`, is registered in memory.
129 /// - [tag] optional, if you use a [tag] to register the Instance. 129 /// - [tag] optional, if you use a [tag] to register the Instance.
130 bool isPrepared<S>({String? tag}) => GetInstance().isPrepared<S>(tag: tag); 130 bool isPrepared<S>({String? tag}) => GetInstance().isPrepared<S>(tag: tag);
  131 +
  132 + /// Replace a parent instance of a class in dependency management
  133 + /// with a [child] instance
  134 + /// - [tag] optional, if you use a [tag] to register the Instance.
  135 + void replace<P>(P child, {String? tag}) {
  136 + final info = GetInstance().getInstanceInfo<P>(tag: tag);
  137 + final permanent = (info.isPermanent ?? false);
  138 + delete<P>(tag: tag, force: permanent);
  139 + put(child, tag: tag, permanent: permanent);
  140 + }
  141 +
  142 + /// Replaces a parent instance with a new Instance<P> lazily from the
  143 + /// [<P>builder()] callback.
  144 + /// - [tag] optional, if you use a [tag] to register the Instance.
  145 + /// - [fenix] optional
  146 + ///
  147 + /// Note: if fenix is not provided it will be set to true if
  148 + /// the parent instance was permanent
  149 + void lazyReplace<P>(InstanceBuilderCallback<P> builder,
  150 + {String? tag, bool? fenix}) {
  151 + final info = GetInstance().getInstanceInfo<P>(tag: tag);
  152 + final permanent = (info.isPermanent ?? false);
  153 + delete<P>(tag: tag, force: permanent);
  154 + lazyPut(builder, tag: tag, fenix: fenix ?? permanent);
  155 + }
131 } 156 }
@@ -31,19 +31,19 @@ class GetInstance { @@ -31,19 +31,19 @@ class GetInstance {
31 T call<T>() => find<T>(); 31 T call<T>() => find<T>();
32 32
33 /// Holds references to every registered Instance when using 33 /// Holds references to every registered Instance when using
34 - /// [Get.put()] 34 + /// `Get.put()`
35 static final Map<String, _InstanceBuilderFactory> _singl = {}; 35 static final Map<String, _InstanceBuilderFactory> _singl = {};
36 36
37 /// Holds a reference to every registered callback when using 37 /// Holds a reference to every registered callback when using
38 - /// [Get.lazyPut()] 38 + /// `Get.lazyPut()`
39 // static final Map<String, _Lazy> _factory = {}; 39 // static final Map<String, _Lazy> _factory = {};
40 40
41 - /// Holds a reference to [Get.reference] when the Instance was 41 + /// Holds a reference to `Get.reference` when the Instance was
42 /// created to manage the memory. 42 /// created to manage the memory.
43 static final Map<String, String?> _routesKey = {}; 43 static final Map<String, String?> _routesKey = {};
44 44
45 - /// Stores the onClose() references of instances created with [Get.create()]  
46 - /// using the [Get.reference]. 45 + /// Stores the onClose() references of instances created with `Get.create()`
  46 + /// using the `Get.reference`.
47 /// Experimental feature to keep the lifecycle and memory management with 47 /// Experimental feature to keep the lifecycle and memory management with
48 /// non-singleton instances. 48 /// non-singleton instances.
49 static final Map<String?, HashSet<Function>> _routesByCreate = {}; 49 static final Map<String?, HashSet<Function>> _routesByCreate = {};
@@ -66,8 +66,8 @@ class GetInstance { @@ -66,8 +66,8 @@ class GetInstance {
66 ); 66 );
67 } 67 }
68 68
69 - /// async version of [Get.put()].  
70 - /// Awaits for the resolution of the Future from [builder()] parameter and 69 + /// async version of `Get.put()`.
  70 + /// Awaits for the resolution of the Future from `builder()` parameter and
71 /// stores the Instance returned. 71 /// stores the Instance returned.
72 Future<S> putAsync<S>( 72 Future<S> putAsync<S>(
73 AsyncInstanceBuilderCallback<S> builder, { 73 AsyncInstanceBuilderCallback<S> builder, {
@@ -77,16 +77,16 @@ class GetInstance { @@ -77,16 +77,16 @@ class GetInstance {
77 return put<S>(await builder(), tag: tag, permanent: permanent); 77 return put<S>(await builder(), tag: tag, permanent: permanent);
78 } 78 }
79 79
80 - /// Injects an instance <[S]> in memory to be globally accessible. 80 + /// Injects an instance `<S>` in memory to be globally accessible.
81 /// 81 ///
82 - /// No need to define the generic type <[S]> as it's inferred from 82 + /// No need to define the generic type `<S>` as it's inferred from
83 /// the [dependency] 83 /// the [dependency]
84 /// 84 ///
85 /// - [dependency] The Instance to be injected. 85 /// - [dependency] The Instance to be injected.
86 /// - [tag] optionally, use a [tag] as an "id" to create multiple records of 86 /// - [tag] optionally, use a [tag] as an "id" to create multiple records of
87 /// the same Type<[S]> 87 /// the same Type<[S]>
88 /// - [permanent] keeps the Instance in memory, not following 88 /// - [permanent] keeps the Instance in memory, not following
89 - /// [Get.smartManagement] rules. 89 + /// `Get.smartManagement` rules.
90 S put<S>( 90 S put<S>(
91 S dependency, { 91 S dependency, {
92 String? tag, 92 String? tag,
@@ -101,27 +101,27 @@ class GetInstance { @@ -101,27 +101,27 @@ class GetInstance {
101 return find<S>(tag: tag); 101 return find<S>(tag: tag);
102 } 102 }
103 103
104 - /// Creates a new Instance<S> lazily from the [<S>builder()] callback. 104 + /// Creates a new Instance<S> lazily from the `<S>builder()` callback.
105 /// 105 ///
106 - /// The first time you call [Get.find()], the [builder()] callback will create 106 + /// The first time you call `Get.find()`, the `builder()` callback will create
107 /// the Instance and persisted as a Singleton (like you would 107 /// the Instance and persisted as a Singleton (like you would
108 - /// use [Get.put()]). 108 + /// use `Get.put()`).
109 /// 109 ///
110 - /// Using [Get.smartManagement] as [SmartManagement.keepFactory] has  
111 - /// the same outcome as using [fenix:true] :  
112 - /// The internal register of [builder()] will remain in memory to recreate  
113 - /// the Instance if the Instance has been removed with [Get.delete()].  
114 - /// Therefore, future calls to [Get.find()] will return the same Instance. 110 + /// Using `Get.smartManagement` as [SmartManagement.keepFactory] has
  111 + /// the same outcome as using `fenix:true` :
  112 + /// The internal register of `builder()` will remain in memory to recreate
  113 + /// the Instance if the Instance has been removed with `Get.delete()`.
  114 + /// Therefore, future calls to `Get.find()` will return the same Instance.
115 /// 115 ///
116 /// If you need to make use of GetxController's life-cycle 116 /// If you need to make use of GetxController's life-cycle
117 - /// ([onInit(), onStart(), onClose()]) [fenix] is a great choice to mix with  
118 - /// [GetBuilder()] and [GetX()] widgets, and/or [GetMaterialApp] Navigation. 117 + /// (`onInit(), onStart(), onClose()`) [fenix] is a great choice to mix with
  118 + /// `GetBuilder()` and `GetX()` widgets, and/or `GetMaterialApp` Navigation.
119 /// 119 ///
120 - /// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead  
121 - /// of [Bindings()] for each [GetPage]. 120 + /// You could use `Get.lazyPut(fenix:true)` in your app's `main()` instead
  121 + /// of `Bindings()` for each `GetPage`.
122 /// And the memory management will be similar. 122 /// And the memory management will be similar.
123 /// 123 ///
124 - /// Subsequent calls to [Get.lazyPut()] with the same parameters 124 + /// Subsequent calls to `Get.lazyPut()` with the same parameters
125 /// (<[S]> and optionally [tag] will **not** override the original). 125 /// (<[S]> and optionally [tag] will **not** override the original).
126 void lazyPut<S>( 126 void lazyPut<S>(
127 InstanceBuilderCallback<S> builder, { 127 InstanceBuilderCallback<S> builder, {
@@ -141,11 +141,11 @@ class GetInstance { @@ -141,11 +141,11 @@ class GetInstance {
141 /// Creates a new Class Instance [S] from the builder callback[S]. 141 /// Creates a new Class Instance [S] from the builder callback[S].
142 /// Every time [find]<[S]>() is used, it calls the builder method to generate 142 /// Every time [find]<[S]>() is used, it calls the builder method to generate
143 /// a new Instance [S]. 143 /// a new Instance [S].
144 - /// It also registers each [instance.onClose()] with the current  
145 - /// Route [Get.reference] to keep the lifecycle active. 144 + /// It also registers each `instance.onClose()` with the current
  145 + /// Route `Get.reference` to keep the lifecycle active.
146 /// Is important to know that the instances created are only stored per Route. 146 /// Is important to know that the instances created are only stored per Route.
147 /// So, if you call `Get.delete<T>()` the "instance factory" used in this 147 /// So, if you call `Get.delete<T>()` the "instance factory" used in this
148 - /// method ([Get.create<T>()]) will be removed, but NOT the instances 148 + /// method (`Get.create<T>()`) will be removed, but NOT the instances
149 /// already created by it. 149 /// already created by it.
150 /// 150 ///
151 /// Example: 151 /// Example:
@@ -167,7 +167,7 @@ class GetInstance { @@ -167,7 +167,7 @@ class GetInstance {
167 ); 167 );
168 } 168 }
169 169
170 - /// Injects the Instance [S] builder into the [_singleton] HashMap. 170 + /// Injects the Instance [S] builder into the `_singleton` HashMap.
171 void _insert<S>({ 171 void _insert<S>({
172 bool? isSingleton, 172 bool? isSingleton,
173 String? name, 173 String? name,
@@ -190,9 +190,9 @@ class GetInstance { @@ -190,9 +190,9 @@ class GetInstance {
190 } 190 }
191 191
192 /// Clears from memory registered Instances associated with [routeName] when 192 /// Clears from memory registered Instances associated with [routeName] when
193 - /// using [Get.smartManagement] as [SmartManagement.full] or 193 + /// using `Get.smartManagement` as [SmartManagement.full] or
194 /// [SmartManagement.keepFactory] 194 /// [SmartManagement.keepFactory]
195 - /// Meant for internal usage of [GetPageRoute] and [GetDialogRoute] 195 + /// Meant for internal usage of `GetPageRoute` and `GetDialogRoute`
196 void removeDependencyByRoute(String routeName) { 196 void removeDependencyByRoute(String routeName) {
197 final keysToRemove = <String>[]; 197 final keysToRemove = <String>[];
198 _routesKey.forEach((key, value) { 198 _routesKey.forEach((key, value) {
@@ -201,11 +201,11 @@ class GetInstance { @@ -201,11 +201,11 @@ class GetInstance {
201 } 201 }
202 }); 202 });
203 203
204 - /// Removes [Get.create()] instances registered in [routeName]. 204 + /// Removes `Get.create()` instances registered in `routeName`.
205 if (_routesByCreate.containsKey(routeName)) { 205 if (_routesByCreate.containsKey(routeName)) {
206 for (final onClose in _routesByCreate[routeName]!) { 206 for (final onClose in _routesByCreate[routeName]!) {
207 // assure the [DisposableInterface] instance holding a reference 207 // assure the [DisposableInterface] instance holding a reference
208 - // to [onClose()] wasn't disposed. 208 + // to onClose() wasn't disposed.
209 onClose(); 209 onClose();
210 } 210 }
211 _routesByCreate[routeName]!.clear(); 211 _routesByCreate[routeName]!.clear();
@@ -214,19 +214,44 @@ class GetInstance { @@ -214,19 +214,44 @@ class GetInstance {
214 214
215 for (final element in keysToRemove) { 215 for (final element in keysToRemove) {
216 delete(key: element); 216 delete(key: element);
  217 + _routesKey.remove(element);
  218 + }
  219 +
  220 + keysToRemove.clear();
  221 + }
  222 +
  223 + void reloadDependencyByRoute(String routeName) {
  224 + final keysToRemove = <String>[];
  225 + _routesKey.forEach((key, value) {
  226 + if (value == routeName) {
  227 + keysToRemove.add(key);
  228 + }
  229 + });
  230 +
  231 + /// Removes `Get.create()` instances registered in `routeName`.
  232 + if (_routesByCreate.containsKey(routeName)) {
  233 + for (final onClose in _routesByCreate[routeName]!) {
  234 + // assure the [DisposableInterface] instance holding a reference
  235 + // to onClose() wasn't disposed.
  236 + onClose();
  237 + }
  238 + _routesByCreate[routeName]!.clear();
  239 + _routesByCreate.remove(routeName);
217 } 240 }
218 241
219 for (final element in keysToRemove) { 242 for (final element in keysToRemove) {
220 - _routesKey.remove(element); 243 + reload(key: element);
  244 + //_routesKey.remove(element);
221 } 245 }
  246 +
222 keysToRemove.clear(); 247 keysToRemove.clear();
223 } 248 }
224 249
225 /// Initializes the dependencies for a Class Instance [S] (or tag), 250 /// Initializes the dependencies for a Class Instance [S] (or tag),
226 /// If its a Controller, it starts the lifecycle process. 251 /// If its a Controller, it starts the lifecycle process.
227 /// Optionally associating the current Route to the lifetime of the instance, 252 /// Optionally associating the current Route to the lifetime of the instance,
228 - /// if [Get.smartManagement] is marked as [SmartManagement.full] or  
229 - /// [Get.keepFactory] 253 + /// if `Get.smartManagement` is marked as [SmartManagement.full] or
  254 + /// [SmartManagement.keepFactory]
230 /// Only flags `isInit` if it's using `Get.create()` 255 /// Only flags `isInit` if it's using `Get.create()`
231 /// (not for Singletons access). 256 /// (not for Singletons access).
232 /// Returns the instance if not initialized, required for Get.create() to 257 /// Returns the instance if not initialized, required for Get.create() to
@@ -248,7 +273,7 @@ class GetInstance { @@ -248,7 +273,7 @@ class GetInstance {
248 } 273 }
249 274
250 /// Links a Class instance [S] (or [tag]) to the current route. 275 /// Links a Class instance [S] (or [tag]) to the current route.
251 - /// Requires usage of [GetMaterialApp]. 276 + /// Requires usage of `GetMaterialApp`.
252 void _registerRouteInstance<S>({String? tag}) { 277 void _registerRouteInstance<S>({String? tag}) {
253 _routesKey.putIfAbsent(_getKey(S, tag), () => Get.reference); 278 _routesKey.putIfAbsent(_getKey(S, tag), () => Get.reference);
254 } 279 }
@@ -353,7 +378,7 @@ class GetInstance { @@ -353,7 +378,7 @@ class GetInstance {
353 } 378 }
354 379
355 /// Delete registered Class Instance [S] (or [tag]) and, closes any open 380 /// Delete registered Class Instance [S] (or [tag]) and, closes any open
356 - /// controllers [DisposableInterface], cleans up the memory 381 + /// controllers `DisposableInterface`, cleans up the memory
357 /// 382 ///
358 /// /// Deletes the Instance<[S]>, cleaning the memory. 383 /// /// Deletes the Instance<[S]>, cleaning the memory.
359 // /// 384 // ///
@@ -362,12 +387,12 @@ class GetInstance { @@ -362,12 +387,12 @@ class GetInstance {
362 // /// the Instance. **don't use** it unless you know what you are doing. 387 // /// the Instance. **don't use** it unless you know what you are doing.
363 388
364 /// Deletes the Instance<[S]>, cleaning the memory and closes any open 389 /// Deletes the Instance<[S]>, cleaning the memory and closes any open
365 - /// controllers ([DisposableInterface]). 390 + /// controllers (`DisposableInterface`).
366 /// 391 ///
367 /// - [tag] Optional "tag" used to register the Instance 392 /// - [tag] Optional "tag" used to register the Instance
368 /// - [key] For internal usage, is the processed key used to register 393 /// - [key] For internal usage, is the processed key used to register
369 /// the Instance. **don't use** it unless you know what you are doing. 394 /// the Instance. **don't use** it unless you know what you are doing.
370 - /// - [force] Will delete an Instance even if marked as [permanent]. 395 + /// - [force] Will delete an Instance even if marked as `permanent`.
371 bool delete<S>({String? tag, String? key, bool force = false}) { 396 bool delete<S>({String? tag, String? key, bool force = false}) {
372 final newKey = key ?? _getKey(S, tag); 397 final newKey = key ?? _getKey(S, tag);
373 398
@@ -413,9 +438,9 @@ class GetInstance { @@ -413,9 +438,9 @@ class GetInstance {
413 } 438 }
414 439
415 /// Delete all registered Class Instances and, closes any open 440 /// Delete all registered Class Instances and, closes any open
416 - /// controllers [DisposableInterface], cleans up the memory 441 + /// controllers `DisposableInterface`, cleans up the memory
417 /// 442 ///
418 - /// - [force] Will delete the Instances even if marked as [permanent]. 443 + /// - [force] Will delete the Instances even if marked as `permanent`.
419 void deleteAll({bool force = false}) { 444 void deleteAll({bool force = false}) {
420 _singl.forEach((key, value) { 445 _singl.forEach((key, value) {
421 delete(key: key, force: force); 446 delete(key: key, force: force);
@@ -448,6 +473,17 @@ class GetInstance { @@ -448,6 +473,17 @@ class GetInstance {
448 return; 473 return;
449 } 474 }
450 475
  476 + final i = builder.dependency;
  477 +
  478 + if (i is GetxServiceMixin && !force) {
  479 + return;
  480 + }
  481 +
  482 + if (i is GetLifeCycleBase) {
  483 + i.onDelete();
  484 + Get.log('"$newKey" onDelete() called');
  485 + }
  486 +
451 builder.dependency = null; 487 builder.dependency = null;
452 builder.isInit = false; 488 builder.isInit = false;
453 Get.log('Instance "$newKey" was restarted.'); 489 Get.log('Instance "$newKey" was restarted.');
@@ -457,7 +493,7 @@ class GetInstance { @@ -457,7 +493,7 @@ class GetInstance {
457 /// - [tag] is optional, if you used a [tag] to register the Instance. 493 /// - [tag] is optional, if you used a [tag] to register the Instance.
458 bool isRegistered<S>({String? tag}) => _singl.containsKey(_getKey(S, tag)); 494 bool isRegistered<S>({String? tag}) => _singl.containsKey(_getKey(S, tag));
459 495
460 - /// Checks if a lazy factory callback ([Get.lazyPut()] that returns an 496 + /// Checks if a lazy factory callback `Get.lazyPut()` that returns an
461 /// Instance<[S]> is registered in memory. 497 /// Instance<[S]> is registered in memory.
462 /// - [tag] is optional, if you used a [tag] to register the lazy Instance. 498 /// - [tag] is optional, if you used a [tag] to register the lazy Instance.
463 bool isPrepared<S>({String? tag}) { 499 bool isPrepared<S>({String? tag}) {
@@ -481,7 +517,7 @@ typedef InjectorBuilderCallback<S> = S Function(GetInstance); @@ -481,7 +517,7 @@ typedef InjectorBuilderCallback<S> = S Function(GetInstance);
481 517
482 typedef AsyncInstanceBuilderCallback<S> = Future<S> Function(); 518 typedef AsyncInstanceBuilderCallback<S> = Future<S> Function();
483 519
484 -/// Internal class to register instances with Get.[put]<[S]>(). 520 +/// Internal class to register instances with `Get.put<S>()`.
485 class _InstanceBuilderFactory<S> { 521 class _InstanceBuilderFactory<S> {
486 /// Marks the Builder as a single instance. 522 /// Marks the Builder as a single instance.
487 /// For reusing [dependency] instead of [builderFunc] 523 /// For reusing [dependency] instead of [builderFunc]
@@ -499,7 +535,7 @@ class _InstanceBuilderFactory<S> { @@ -499,7 +535,7 @@ class _InstanceBuilderFactory<S> {
499 InstanceBuilderCallback<S> builderFunc; 535 InstanceBuilderCallback<S> builderFunc;
500 536
501 /// Flag to persist the instance in memory, 537 /// Flag to persist the instance in memory,
502 - /// without considering [Get.smartManagement] 538 + /// without considering `Get.smartManagement`
503 bool permanent = false; 539 bool permanent = false;
504 540
505 bool isInit = false; 541 bool isInit = false;
@@ -3,7 +3,7 @@ import '../../get_core/get_core.dart'; @@ -3,7 +3,7 @@ import '../../get_core/get_core.dart';
3 /// Special callable class to keep the contract of a regular method, and avoid 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 4 /// overrides if you extend the class that uses it, as Dart has no final
5 /// methods. 5 /// methods.
6 -/// Used in [DisposableInterface] to avoid the danger of overriding onStart. 6 +/// Used in `DisposableInterface` to avoid the danger of overriding onStart.
7 class InternalFinalCallback<T> { 7 class InternalFinalCallback<T> {
8 ValueUpdater<T>? _callback; 8 ValueUpdater<T>? _callback;
9 9
@@ -205,6 +205,52 @@ extension ExtensionSnackbar on GetInterface { @@ -205,6 +205,52 @@ extension ExtensionSnackbar on GetInterface {
205 } 205 }
206 } 206 }
207 207
  208 +extension OverlayExt on GetInterface {
  209 + Future<T> showOverlay<T>({
  210 + required Future<T> Function() asyncFunction,
  211 + Color opacityColor = Colors.black,
  212 + Widget? loadingWidget,
  213 + double opacity = .5,
  214 + }) async {
  215 + final navigatorState =
  216 + Navigator.of(Get.overlayContext!, rootNavigator: false);
  217 + final overlayState = navigatorState.overlay!;
  218 +
  219 + final overlayEntryOpacity = OverlayEntry(builder: (context) {
  220 + return Opacity(
  221 + opacity: opacity,
  222 + child: Container(
  223 + color: opacityColor,
  224 + ));
  225 + });
  226 + final overlayEntryLoader = OverlayEntry(builder: (context) {
  227 + return loadingWidget ??
  228 + Center(
  229 + child: Container(
  230 + height: 90,
  231 + width: 90,
  232 + child: Text('Loading...'),
  233 + ));
  234 + });
  235 + overlayState.insert(overlayEntryOpacity);
  236 + overlayState.insert(overlayEntryLoader);
  237 +
  238 + T data;
  239 +
  240 + try {
  241 + data = await asyncFunction();
  242 + } on Exception catch (_) {
  243 + overlayEntryLoader.remove();
  244 + overlayEntryOpacity.remove();
  245 + rethrow;
  246 + }
  247 +
  248 + overlayEntryLoader.remove();
  249 + overlayEntryOpacity.remove();
  250 + return data;
  251 + }
  252 +}
  253 +
208 extension ExtensionDialog on GetInterface { 254 extension ExtensionDialog on GetInterface {
209 /// Show a dialog. 255 /// Show a dialog.
210 /// You can pass a [transitionDuration] and/or [transitionCurve], 256 /// You can pass a [transitionDuration] and/or [transitionCurve],
@@ -215,7 +261,7 @@ extension ExtensionDialog on GetInterface { @@ -215,7 +261,7 @@ extension ExtensionDialog on GetInterface {
215 bool barrierDismissible = true, 261 bool barrierDismissible = true,
216 Color? barrierColor, 262 Color? barrierColor,
217 bool useSafeArea = true, 263 bool useSafeArea = true,
218 - bool useRootNavigator = true, 264 + GlobalKey<NavigatorState>? navigatorKey,
219 Object? arguments, 265 Object? arguments,
220 Duration? transitionDuration, 266 Duration? transitionDuration,
221 Curve? transitionCurve, 267 Curve? transitionCurve,
@@ -250,7 +296,7 @@ extension ExtensionDialog on GetInterface { @@ -250,7 +296,7 @@ extension ExtensionDialog on GetInterface {
250 child: child, 296 child: child,
251 ); 297 );
252 }, 298 },
253 - useRootNavigator: useRootNavigator, 299 + navigatorKey: navigatorKey,
254 routeSettings: 300 routeSettings:
255 routeSettings ?? RouteSettings(arguments: arguments, name: name), 301 routeSettings ?? RouteSettings(arguments: arguments, name: name),
256 ); 302 );
@@ -264,20 +310,25 @@ extension ExtensionDialog on GetInterface { @@ -264,20 +310,25 @@ extension ExtensionDialog on GetInterface {
264 Color barrierColor = const Color(0x80000000), 310 Color barrierColor = const Color(0x80000000),
265 Duration transitionDuration = const Duration(milliseconds: 200), 311 Duration transitionDuration = const Duration(milliseconds: 200),
266 RouteTransitionsBuilder? transitionBuilder, 312 RouteTransitionsBuilder? transitionBuilder,
267 - bool useRootNavigator = true, 313 + GlobalKey<NavigatorState>? navigatorKey,
268 RouteSettings? routeSettings, 314 RouteSettings? routeSettings,
269 }) { 315 }) {
270 assert(!barrierDismissible || barrierLabel != null); 316 assert(!barrierDismissible || barrierLabel != null);
271 - return Navigator.of(overlayContext!, rootNavigator: useRootNavigator)  
272 - .push<T>(GetDialogRoute<T>(  
273 - pageBuilder: pageBuilder,  
274 - barrierDismissible: barrierDismissible,  
275 - barrierLabel: barrierLabel,  
276 - barrierColor: barrierColor,  
277 - transitionDuration: transitionDuration,  
278 - transitionBuilder: transitionBuilder,  
279 - settings: routeSettings,  
280 - )); 317 + final nav = navigatorKey?.currentState ??
  318 + Navigator.of(overlayContext!,
  319 + rootNavigator:
  320 + true); //overlay context will always return the root navigator
  321 + return nav.push<T>(
  322 + GetDialogRoute<T>(
  323 + pageBuilder: pageBuilder,
  324 + barrierDismissible: barrierDismissible,
  325 + barrierLabel: barrierLabel,
  326 + barrierColor: barrierColor,
  327 + transitionDuration: transitionDuration,
  328 + transitionBuilder: transitionBuilder,
  329 + settings: routeSettings,
  330 + ),
  331 + );
281 } 332 }
282 333
283 /// Custom UI Dialog. 334 /// Custom UI Dialog.
@@ -309,6 +360,9 @@ extension ExtensionDialog on GetInterface { @@ -309,6 +360,9 @@ extension ExtensionDialog on GetInterface {
309 360
310 // onWillPop Scope 361 // onWillPop Scope
311 WillPopCallback? onWillPop, 362 WillPopCallback? onWillPop,
  363 +
  364 + // the navigator used to push the dialog
  365 + GlobalKey<NavigatorState>? navigatorKey,
312 }) { 366 }) {
313 var leanCancel = onCancel != null || textCancel != null; 367 var leanCancel = onCancel != null || textCancel != null;
314 var leanConfirm = onConfirm != null || textConfirm != null; 368 var leanConfirm = onConfirm != null || textConfirm != null;
@@ -394,19 +448,15 @@ extension ExtensionDialog on GetInterface { @@ -394,19 +448,15 @@ extension ExtensionDialog on GetInterface {
394 buttonPadding: EdgeInsets.zero, 448 buttonPadding: EdgeInsets.zero,
395 ); 449 );
396 450
397 - if (onWillPop != null) {  
398 - return dialog<T>(  
399 - WillPopScope(  
400 - onWillPop: onWillPop,  
401 - child: baseAlertDialog,  
402 - ),  
403 - barrierDismissible: barrierDismissible,  
404 - );  
405 - }  
406 -  
407 return dialog<T>( 451 return dialog<T>(
408 - baseAlertDialog, 452 + onWillPop != null
  453 + ? WillPopScope(
  454 + onWillPop: onWillPop,
  455 + child: baseAlertDialog,
  456 + )
  457 + : baseAlertDialog,
409 barrierDismissible: barrierDismissible, 458 barrierDismissible: barrierDismissible,
  459 + navigatorKey: navigatorKey,
410 ); 460 );
411 } 461 }
412 } 462 }
@@ -460,7 +510,7 @@ extension ExtensionBottomSheet on GetInterface { @@ -460,7 +510,7 @@ extension ExtensionBottomSheet on GetInterface {
460 extension GetNavigation on GetInterface { 510 extension GetNavigation on GetInterface {
461 /// **Navigation.push()** shortcut.<br><br> 511 /// **Navigation.push()** shortcut.<br><br>
462 /// 512 ///
463 - /// Pushes a new [page] to the stack 513 + /// Pushes a new `page` to the stack
464 /// 514 ///
465 /// It has the advantage of not needing context, 515 /// It has the advantage of not needing context,
466 /// so you can call from your business logic 516 /// so you can call from your business logic
@@ -494,6 +544,7 @@ extension GetNavigation on GetInterface { @@ -494,6 +544,7 @@ extension GetNavigation on GetInterface {
494 Bindings? binding, 544 Bindings? binding,
495 bool preventDuplicates = true, 545 bool preventDuplicates = true,
496 bool? popGesture, 546 bool? popGesture,
  547 + double gestureWidth = 20,
497 }) { 548 }) {
498 var routeName = "/${page.runtimeType.toString()}"; 549 var routeName = "/${page.runtimeType.toString()}";
499 if (preventDuplicates && routeName == currentRoute) { 550 if (preventDuplicates && routeName == currentRoute) {
@@ -504,6 +555,7 @@ extension GetNavigation on GetInterface { @@ -504,6 +555,7 @@ extension GetNavigation on GetInterface {
504 opaque: opaque ?? true, 555 opaque: opaque ?? true,
505 page: _resolve(page, 'to'), 556 page: _resolve(page, 'to'),
506 routeName: routeName, 557 routeName: routeName,
  558 + gestureWidth: gestureWidth,
507 settings: RouteSettings( 559 settings: RouteSettings(
508 // name: forceRouteName ? '${a.runtimeType}' : '', 560 // name: forceRouteName ? '${a.runtimeType}' : '',
509 arguments: arguments, 561 arguments: arguments,
@@ -538,7 +590,7 @@ you can only use widgets and widget functions here'''; @@ -538,7 +590,7 @@ you can only use widgets and widget functions here''';
538 590
539 /// **Navigation.pushNamed()** shortcut.<br><br> 591 /// **Navigation.pushNamed()** shortcut.<br><br>
540 /// 592 ///
541 - /// Pushes a new named [page] to the stack. 593 + /// Pushes a new named `page` to the stack.
542 /// 594 ///
543 /// It has the advantage of not needing context, so you can call 595 /// It has the advantage of not needing context, so you can call
544 /// from your business logic. 596 /// from your business logic.
@@ -576,7 +628,7 @@ you can only use widgets and widget functions here'''; @@ -576,7 +628,7 @@ you can only use widgets and widget functions here''';
576 628
577 /// **Navigation.pushReplacementNamed()** shortcut.<br><br> 629 /// **Navigation.pushReplacementNamed()** shortcut.<br><br>
578 /// 630 ///
579 - /// Pop the current named [page] in the stack and push a new one in its place 631 + /// Pop the current named `page` in the stack and push a new one in its place
580 /// 632 ///
581 /// It has the advantage of not needing context, so you can call 633 /// It has the advantage of not needing context, so you can call
582 /// from your business logic. 634 /// from your business logic.
@@ -632,7 +684,7 @@ you can only use widgets and widget functions here'''; @@ -632,7 +684,7 @@ you can only use widgets and widget functions here''';
632 684
633 /// **Navigation.pushAndRemoveUntil()** shortcut.<br><br> 685 /// **Navigation.pushAndRemoveUntil()** shortcut.<br><br>
634 /// 686 ///
635 - /// Push the given [page], and then pop several pages in the stack until 687 + /// Push the given `page`, and then pop several pages in the stack until
636 /// [predicate] returns true 688 /// [predicate] returns true
637 /// 689 ///
638 /// [id] is for when you are using nested navigation, 690 /// [id] is for when you are using nested navigation,
@@ -656,7 +708,7 @@ you can only use widgets and widget functions here'''; @@ -656,7 +708,7 @@ you can only use widgets and widget functions here''';
656 708
657 /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> 709 /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
658 /// 710 ///
659 - /// Push the given named [page], and then pop several pages in the stack 711 + /// Push the given named `page`, and then pop several pages in the stack
660 /// until [predicate] returns true 712 /// until [predicate] returns true
661 /// 713 ///
662 /// You can send any type of value to the other route in the [arguments]. 714 /// You can send any type of value to the other route in the [arguments].
@@ -693,7 +745,7 @@ you can only use widgets and widget functions here'''; @@ -693,7 +745,7 @@ you can only use widgets and widget functions here''';
693 745
694 /// **Navigation.popAndPushNamed()** shortcut.<br><br> 746 /// **Navigation.popAndPushNamed()** shortcut.<br><br>
695 /// 747 ///
696 - /// Pop the current named page and pushes a new [page] to the stack 748 + /// Pop the current named page and pushes a new `page` to the stack
697 /// in its place 749 /// in its place
698 /// 750 ///
699 /// You can send any type of value to the other route in the [arguments]. 751 /// You can send any type of value to the other route in the [arguments].
@@ -732,7 +784,7 @@ you can only use widgets and widget functions here'''; @@ -732,7 +784,7 @@ you can only use widgets and widget functions here''';
732 784
733 /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> 785 /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
734 /// 786 ///
735 - /// Push a named [page] and pop several pages in the stack 787 + /// Push a named `page` and pop several pages in the stack
736 /// until [predicate] returns true. [predicate] is optional 788 /// until [predicate] returns true. [predicate] is optional
737 /// 789 ///
738 /// It has the advantage of not needing context, so you can 790 /// It has the advantage of not needing context, so you can
@@ -827,7 +879,7 @@ you can only use widgets and widget functions here'''; @@ -827,7 +879,7 @@ you can only use widgets and widget functions here''';
827 879
828 /// **Navigation.pushReplacement()** shortcut .<br><br> 880 /// **Navigation.pushReplacement()** shortcut .<br><br>
829 /// 881 ///
830 - /// Pop the current page and pushes a new [page] to the stack 882 + /// Pop the current page and pushes a new `page` to the stack
831 /// 883 ///
832 /// It has the advantage of not needing context, 884 /// It has the advantage of not needing context,
833 /// so you can call from your business logic 885 /// so you can call from your business logic
@@ -862,6 +914,7 @@ you can only use widgets and widget functions here'''; @@ -862,6 +914,7 @@ you can only use widgets and widget functions here''';
862 bool fullscreenDialog = false, 914 bool fullscreenDialog = false,
863 bool preventDuplicates = true, 915 bool preventDuplicates = true,
864 Duration? duration, 916 Duration? duration,
  917 + double gestureWidth = 20,
865 }) { 918 }) {
866 var routeName = "/${page.runtimeType.toString()}"; 919 var routeName = "/${page.runtimeType.toString()}";
867 if (preventDuplicates && routeName == currentRoute) { 920 if (preventDuplicates && routeName == currentRoute) {
@@ -869,6 +922,7 @@ you can only use widgets and widget functions here'''; @@ -869,6 +922,7 @@ you can only use widgets and widget functions here''';
869 } 922 }
870 return global(id).currentState?.pushReplacement(GetPageRoute( 923 return global(id).currentState?.pushReplacement(GetPageRoute(
871 opaque: opaque, 924 opaque: opaque,
  925 + gestureWidth: gestureWidth,
872 page: _resolve(page, 'off'), 926 page: _resolve(page, 'off'),
873 binding: binding, 927 binding: binding,
874 settings: RouteSettings(arguments: arguments), 928 settings: RouteSettings(arguments: arguments),
@@ -882,7 +936,7 @@ you can only use widgets and widget functions here'''; @@ -882,7 +936,7 @@ you can only use widgets and widget functions here''';
882 936
883 /// **Navigation.pushAndRemoveUntil()** shortcut .<br><br> 937 /// **Navigation.pushAndRemoveUntil()** shortcut .<br><br>
884 /// 938 ///
885 - /// Push a [page] and pop several pages in the stack 939 + /// Push a `page` and pop several pages in the stack
886 /// until [predicate] returns true. [predicate] is optional 940 /// until [predicate] returns true. [predicate] is optional
887 /// 941 ///
888 /// It has the advantage of not needing context, 942 /// It has the advantage of not needing context,
@@ -923,6 +977,7 @@ you can only use widgets and widget functions here'''; @@ -923,6 +977,7 @@ you can only use widgets and widget functions here''';
923 Transition? transition, 977 Transition? transition,
924 Curve? curve, 978 Curve? curve,
925 Duration? duration, 979 Duration? duration,
  980 + double gestureWidth = 20,
926 }) { 981 }) {
927 var routeName = "/${page.runtimeType.toString()}"; 982 var routeName = "/${page.runtimeType.toString()}";
928 983
@@ -932,6 +987,7 @@ you can only use widgets and widget functions here'''; @@ -932,6 +987,7 @@ you can only use widgets and widget functions here''';
932 popGesture: popGesture ?? defaultPopGesture, 987 popGesture: popGesture ?? defaultPopGesture,
933 page: _resolve(page, 'offAll'), 988 page: _resolve(page, 'offAll'),
934 binding: binding, 989 binding: binding,
  990 + gestureWidth: gestureWidth,
935 settings: RouteSettings(arguments: arguments), 991 settings: RouteSettings(arguments: arguments),
936 fullscreenDialog: fullscreenDialog, 992 fullscreenDialog: fullscreenDialog,
937 routeName: routeName, 993 routeName: routeName,
@@ -942,23 +998,6 @@ you can only use widgets and widget functions here'''; @@ -942,23 +998,6 @@ you can only use widgets and widget functions here''';
942 predicate ?? (route) => false); 998 predicate ?? (route) => false);
943 } 999 }
944 1000
945 - void registerRoutes(List<GetPage> getPages) {  
946 - //TODO: only replace if null???  
947 - routeTree = ParseRouteTree(routes: <GetPage>[]);  
948 - routeTree.addRoutes(getPages);  
949 - }  
950 -  
951 - void addPages(List<GetPage>? getPages) {  
952 - if (getPages != null) {  
953 - registerRoutes(getPages);  
954 - }  
955 - }  
956 -  
957 - void addPage(GetPage getPage) {  
958 - // routeTree = ParseRouteTree();  
959 - routeTree.addRoute(getPage);  
960 - }  
961 -  
962 /// change default config of Get 1001 /// change default config of Get
963 void config( 1002 void config(
964 {bool? enableLog, 1003 {bool? enableLog,
@@ -1022,12 +1061,16 @@ you can only use widgets and widget functions here'''; @@ -1022,12 +1061,16 @@ you can only use widgets and widget functions here''';
1022 } 1061 }
1023 1062
1024 GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { 1063 GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
1025 - getxController.key = newKey;  
1026 - return key; 1064 + return getxController.addKey(newKey);
1027 } 1065 }
1028 1066
1029 GlobalKey<NavigatorState>? nestedKey(dynamic key) { 1067 GlobalKey<NavigatorState>? nestedKey(dynamic key) {
1030 - keys.putIfAbsent(key, () => GlobalKey<NavigatorState>()); 1068 + keys.putIfAbsent(
  1069 + key,
  1070 + () => GlobalKey<NavigatorState>(
  1071 + debugLabel: 'Getx nested key: ${key.toString()}',
  1072 + ),
  1073 + );
1031 return keys[key]; 1074 return keys[key];
1032 } 1075 }
1033 1076
@@ -1054,19 +1097,6 @@ you can only use widgets and widget functions here'''; @@ -1054,19 +1097,6 @@ you can only use widgets and widget functions here''';
1054 1097
1055 return _key; 1098 return _key;
1056 } 1099 }
1057 -  
1058 - /// Casts the stored router delegate to a desired type  
1059 - TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>  
1060 - _routerDelegate as TDelegate?;  
1061 -  
1062 - static RouterDelegate? _routerDelegate;  
1063 -  
1064 - // ignore: use_setters_to_change_properties  
1065 - void setDefaultDelegate(RouterDelegate? delegate) {  
1066 - _routerDelegate = delegate;  
1067 - }  
1068 -  
1069 - GetDelegate? getDelegate() => delegate<GetDelegate, GetNavConfig>();  
1070 1100
1071 /// give current arguments 1101 /// give current arguments
1072 dynamic get arguments => routing.args; 1102 dynamic get arguments => routing.args;
@@ -1207,9 +1237,6 @@ you can only use widgets and widget functions here'''; @@ -1207,9 +1237,6 @@ you can only use widgets and widget functions here''';
1207 set parameters(Map<String, String?> newParameters) => 1237 set parameters(Map<String, String?> newParameters) =>
1208 getxController.parameters = newParameters; 1238 getxController.parameters = newParameters;
1209 1239
1210 - ParseRouteTree get routeTree => getxController.routeTree;  
1211 - set routeTree(ParseRouteTree tree) => getxController.routeTree = tree;  
1212 -  
1213 CustomTransition? get customTransition => getxController.customTransition; 1240 CustomTransition? get customTransition => getxController.customTransition;
1214 set customTransition(CustomTransition? newTransition) => 1241 set customTransition(CustomTransition? newTransition) =>
1215 getxController.customTransition = newTransition; 1242 getxController.customTransition = newTransition;
@@ -1220,6 +1247,65 @@ you can only use widgets and widget functions here'''; @@ -1220,6 +1247,65 @@ you can only use widgets and widget functions here''';
1220 static GetMaterialController getxController = GetMaterialController(); 1247 static GetMaterialController getxController = GetMaterialController();
1221 } 1248 }
1222 1249
  1250 +extension NavTwoExt on GetInterface {
  1251 + void addPages(List<GetPage> getPages) {
  1252 + routeTree.addRoutes(getPages);
  1253 + }
  1254 +
  1255 + static late final _routeTree = ParseRouteTree(routes: []);
  1256 +
  1257 + ParseRouteTree get routeTree => _routeTree;
  1258 + void addPage(GetPage getPage) {
  1259 + routeTree.addRoute(getPage);
  1260 + }
  1261 +
  1262 + /// Casts the stored router delegate to a desired type
  1263 + TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>
  1264 + routerDelegate as TDelegate?;
  1265 +
  1266 + // // ignore: use_setters_to_change_properties
  1267 + // void setDefaultDelegate(RouterDelegate? delegate) {
  1268 + // _routerDelegate = delegate;
  1269 + // }
  1270 +
  1271 + // GetDelegate? getDelegate() => delegate<GetDelegate, GetNavConfig>();
  1272 +
  1273 + GetInformationParser createInformationParser({String initialRoute = '/'}) {
  1274 + if (routeInformationParser == null) {
  1275 + return routeInformationParser = GetInformationParser(
  1276 + initialRoute: initialRoute,
  1277 + );
  1278 + } else {
  1279 + return routeInformationParser as GetInformationParser;
  1280 + }
  1281 + }
  1282 +
  1283 + // static GetDelegate? _delegate;
  1284 +
  1285 + GetDelegate get rootDelegate => createDelegate();
  1286 +
  1287 + GetDelegate createDelegate({
  1288 + GetPage<dynamic>? notFoundRoute,
  1289 + List<NavigatorObserver>? navigatorObservers,
  1290 + TransitionDelegate<dynamic>? transitionDelegate,
  1291 + PopMode backButtonPopMode = PopMode.History,
  1292 + PreventDuplicateHandlingMode preventDuplicateHandlingMode =
  1293 + PreventDuplicateHandlingMode.ReorderRoutes,
  1294 + }) {
  1295 + if (routerDelegate == null) {
  1296 + return routerDelegate = GetDelegate(
  1297 + notFoundRoute: notFoundRoute,
  1298 + navigatorObservers: navigatorObservers,
  1299 + transitionDelegate: transitionDelegate,
  1300 + backButtonPopMode: backButtonPopMode,
  1301 + preventDuplicateHandlingMode: preventDuplicateHandlingMode,
  1302 + );
  1303 + } else {
  1304 + return routerDelegate as GetDelegate;
  1305 + }
  1306 + }
  1307 +}
  1308 +
1223 /// It replaces the Flutter Navigator, but needs no context. 1309 /// It replaces the Flutter Navigator, but needs no context.
1224 /// You can to use navigator.push(YourRoute()) rather 1310 /// You can to use navigator.push(YourRoute()) rather
1225 /// Navigator.push(context, YourRoute()); 1311 /// Navigator.push(context, YourRoute());
@@ -7,7 +7,9 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { @@ -7,7 +7,9 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> {
7 7
8 GetInformationParser({ 8 GetInformationParser({
9 this.initialRoute = '/', 9 this.initialRoute = '/',
10 - }); 10 + }) {
  11 + Get.log('GetInformationParser is created !');
  12 + }
11 @override 13 @override
12 SynchronousFuture<GetNavConfig> parseRouteInformation( 14 SynchronousFuture<GetNavConfig> parseRouteInformation(
13 RouteInformation routeInformation, 15 RouteInformation routeInformation,
@@ -2,6 +2,22 @@ import 'package:flutter/widgets.dart'; @@ -2,6 +2,22 @@ import 'package:flutter/widgets.dart';
2 2
3 import '../../../get.dart'; 3 import '../../../get.dart';
4 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 +
5 /// This config enables us to navigate directly to a sub-url 21 /// This config enables us to navigate directly to a sub-url
6 class GetNavConfig extends RouteInformation { 22 class GetNavConfig extends RouteInformation {
7 final List<GetPage> currentTreeBranch; 23 final List<GetPage> currentTreeBranch;
@@ -18,7 +34,6 @@ class GetNavConfig extends RouteInformation { @@ -18,7 +34,6 @@ class GetNavConfig extends RouteInformation {
18 34
19 GetNavConfig copyWith({ 35 GetNavConfig copyWith({
20 List<GetPage>? currentTreeBranch, 36 List<GetPage>? currentTreeBranch,
21 - GetPage? currentPage,  
22 required String? location, 37 required String? location,
23 required Object? state, 38 required Object? state,
24 }) { 39 }) {
@@ -29,6 +44,16 @@ class GetNavConfig extends RouteInformation { @@ -29,6 +44,16 @@ class GetNavConfig extends RouteInformation {
29 ); 44 );
30 } 45 }
31 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 +
32 @override 57 @override
33 String toString() => ''' 58 String toString() => '''
34 ======GetNavConfig=====\ncurrentTreeBranch: $currentTreeBranch\ncurrentPage: $currentPage\n======GetNavConfig====='''; 59 ======GetNavConfig=====\ncurrentTreeBranch: $currentTreeBranch\ncurrentPage: $currentPage\n======GetNavConfig=====''';
@@ -38,6 +38,12 @@ enum PreventDuplicateHandlingMode { @@ -38,6 +38,12 @@ enum PreventDuplicateHandlingMode {
38 38
39 /// Simply don't push the new route 39 /// Simply don't push the new route
40 DoNothing, 40 DoNothing,
  41 +
  42 + /// Recommended - Moves the old route entry to the front
  43 + ///
  44 + /// With this mode, you guarantee there will be only one
  45 + /// route entry for each location
  46 + ReorderRoutes
41 } 47 }
42 48
43 class GetDelegate extends RouterDelegate<GetNavConfig> 49 class GetDelegate extends RouterDelegate<GetNavConfig>
@@ -46,58 +52,116 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -46,58 +52,116 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
46 final PopMode backButtonPopMode; 52 final PopMode backButtonPopMode;
47 final PreventDuplicateHandlingMode preventDuplicateHandlingMode; 53 final PreventDuplicateHandlingMode preventDuplicateHandlingMode;
48 54
49 - GetPage? notFoundRoute; 55 + final GetPage notFoundRoute;
50 56
51 final List<NavigatorObserver>? navigatorObservers; 57 final List<NavigatorObserver>? navigatorObservers;
52 final TransitionDelegate<dynamic>? transitionDelegate; 58 final TransitionDelegate<dynamic>? transitionDelegate;
53 - final _resultCompleter = <GetNavConfig, Completer<Object?>>{};  
54 59
55 GlobalKey<NavigatorState> get navigatorKey => 60 GlobalKey<NavigatorState> get navigatorKey =>
56 GetNavigation.getxController.key; 61 GetNavigation.getxController.key;
57 62
58 GetDelegate({ 63 GetDelegate({
59 - this.notFoundRoute, 64 + GetPage? notFoundRoute,
60 this.navigatorObservers, 65 this.navigatorObservers,
61 this.transitionDelegate, 66 this.transitionDelegate,
62 this.backButtonPopMode = PopMode.History, 67 this.backButtonPopMode = PopMode.History,
63 - this.preventDuplicateHandlingMode = PreventDuplicateHandlingMode.DoNothing,  
64 - }); 68 + this.preventDuplicateHandlingMode =
  69 + PreventDuplicateHandlingMode.ReorderRoutes,
  70 + }) : notFoundRoute = notFoundRoute ??
  71 + GetPage(
  72 + name: '/404',
  73 + page: () => Scaffold(
  74 + body: Text('Route not found'),
  75 + ),
  76 + ) {
  77 + Get.log('GetDelegate is created !');
  78 + }
  79 +
  80 + Future<GetNavConfig?> runMiddleware(GetNavConfig config) async {
  81 + final middlewares = config.currentTreeBranch.last.middlewares;
  82 + if (middlewares == null) {
  83 + return config;
  84 + }
  85 + var iterator = config;
  86 + for (var item in middlewares) {
  87 + var redirectRes = await item.redirectDelegate(iterator);
  88 + if (redirectRes == null) return null;
  89 + iterator = redirectRes;
  90 + }
  91 + return iterator;
  92 + }
  93 +
  94 + Future<void> _unsafeHistoryAdd(GetNavConfig config) async {
  95 + final res = await runMiddleware(config);
  96 + if (res == null) return;
  97 + history.add(res);
  98 + }
  99 +
  100 + Future<void> _unsafeHistoryRemove(GetNavConfig config) async {
  101 + var index = history.indexOf(config);
  102 + if (index >= 0) await _unsafeHistoryRemoveAt(index);
  103 + }
  104 +
  105 + Future<GetNavConfig?> _unsafeHistoryRemoveAt(int index) async {
  106 + if (index == history.length - 1 && history.length > 1) {
  107 + //removing WILL update the current route
  108 + final toCheck = history[history.length - 2];
  109 + final resMiddleware = await runMiddleware(toCheck);
  110 + if (resMiddleware == null) return null;
  111 + history[history.length - 2] = resMiddleware;
  112 + }
  113 + return history.removeAt(index);
  114 + }
  115 +
  116 + T arguments<T>() {
  117 + return currentConfiguration?.currentPage?.arguments as T;
  118 + }
  119 +
  120 + Map<String, String> get parameters {
  121 + return currentConfiguration?.currentPage?.parameters ?? {};
  122 + }
  123 +
  124 + // void _unsafeHistoryClear() {
  125 + // history.clear();
  126 + // }
65 127
66 /// Adds a new history entry and waits for the result 128 /// Adds a new history entry and waits for the result
67 - Future<T?> pushHistory<T>( 129 + Future<void> pushHistory(
68 GetNavConfig config, { 130 GetNavConfig config, {
69 bool rebuildStack = true, 131 bool rebuildStack = true,
70 - }) { 132 + }) async {
71 //this changes the currentConfiguration 133 //this changes the currentConfiguration
72 - final completer = Completer<T?>();  
73 - _resultCompleter[config] = completer;  
74 - _pushHistory(config); 134 + await _pushHistory(config);
75 if (rebuildStack) { 135 if (rebuildStack) {
76 refresh(); 136 refresh();
77 } 137 }
78 - return completer.future;  
79 } 138 }
80 139
81 - void _removeHistoryEntry(GetNavConfig entry) {  
82 - history.remove(entry);  
83 - final lastCompleter = _resultCompleter.remove(entry);  
84 - lastCompleter?.complete(entry); 140 + Future<void> _removeHistoryEntry(GetNavConfig entry) async {
  141 + await _unsafeHistoryRemove(entry);
85 } 142 }
86 143
87 - void _pushHistory(GetNavConfig config) { 144 + Future<void> _pushHistory(GetNavConfig config) async {
88 if (config.currentPage!.preventDuplicates) { 145 if (config.currentPage!.preventDuplicates) {
89 - if (history.any((element) => element.location == config.location)) { 146 + final originalEntryIndex =
  147 + history.indexWhere((element) => element.location == config.location);
  148 + if (originalEntryIndex >= 0) {
90 switch (preventDuplicateHandlingMode) { 149 switch (preventDuplicateHandlingMode) {
91 case PreventDuplicateHandlingMode.PopUntilOriginalRoute: 150 case PreventDuplicateHandlingMode.PopUntilOriginalRoute:
92 - until(config.location!, popMode: PopMode.Page);  
93 - return; 151 + await backUntil(config.location!, popMode: PopMode.Page);
  152 + break;
  153 + case PreventDuplicateHandlingMode.ReorderRoutes:
  154 + await _unsafeHistoryRemoveAt(originalEntryIndex);
  155 + await _unsafeHistoryAdd(config);
  156 + break;
94 case PreventDuplicateHandlingMode.DoNothing: 157 case PreventDuplicateHandlingMode.DoNothing:
95 default: 158 default:
96 - return; 159 + break;
97 } 160 }
  161 + return;
98 } 162 }
99 } 163 }
100 - history.add(config); 164 + await _unsafeHistoryAdd(config);
101 } 165 }
102 166
103 // GetPageRoute getPageRoute(RouteSettings? settings) { 167 // GetPageRoute getPageRoute(RouteSettings? settings) {
@@ -105,34 +169,33 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -105,34 +169,33 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
105 // .page(); 169 // .page();
106 // } 170 // }
107 171
108 - GetNavConfig? _popHistory() { 172 + Future<GetNavConfig?> _popHistory() async {
109 if (!_canPopHistory()) return null; 173 if (!_canPopHistory()) return null;
110 - return _doPopHistory(); 174 + return await _doPopHistory();
111 } 175 }
112 176
113 - GetNavConfig _doPopHistory() {  
114 - final res = history.removeLast();  
115 - return res; 177 + Future<GetNavConfig?> _doPopHistory() async {
  178 + return await _unsafeHistoryRemoveAt(history.length - 1);
116 } 179 }
117 180
118 - GetNavConfig? _popPage() { 181 + Future<GetNavConfig?> _popPage() async {
119 if (!_canPopPage()) return null; 182 if (!_canPopPage()) return null;
120 - return _doPopPage(); 183 + return await _doPopPage();
121 } 184 }
122 185
123 - GetNavConfig? _pop(PopMode mode) { 186 + Future<GetNavConfig?> _pop(PopMode mode) async {
124 switch (mode) { 187 switch (mode) {
125 case PopMode.History: 188 case PopMode.History:
126 - return _popHistory(); 189 + return await _popHistory();
127 case PopMode.Page: 190 case PopMode.Page:
128 - return _popPage(); 191 + return await _popPage();
129 default: 192 default:
130 return null; 193 return null;
131 } 194 }
132 } 195 }
133 196
134 // returns the popped page 197 // returns the popped page
135 - GetNavConfig? _doPopPage() { 198 + Future<GetNavConfig?> _doPopPage() async {
136 final currentBranch = currentConfiguration?.currentTreeBranch; 199 final currentBranch = currentConfiguration?.currentTreeBranch;
137 if (currentBranch != null && currentBranch.length > 1) { 200 if (currentBranch != null && currentBranch.length > 1) {
138 //remove last part only 201 //remove last part only
@@ -147,13 +210,13 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -147,13 +210,13 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
147 final prevLocation = prevHistoryEntry.location; 210 final prevLocation = prevHistoryEntry.location;
148 if (newLocation == prevLocation) { 211 if (newLocation == prevLocation) {
149 //pop the entire history entry 212 //pop the entire history entry
150 - return _popHistory(); 213 + return await _popHistory();
151 } 214 }
152 } 215 }
153 216
154 //create a new route with the remaining tree branch 217 //create a new route with the remaining tree branch
155 - final res = _popHistory();  
156 - _pushHistory( 218 + final res = await _popHistory();
  219 + await _pushHistory(
157 GetNavConfig( 220 GetNavConfig(
158 currentTreeBranch: remaining.toList(), 221 currentTreeBranch: remaining.toList(),
159 location: remaining.last.name, 222 location: remaining.last.name,
@@ -163,16 +226,16 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -163,16 +226,16 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
163 return res; 226 return res;
164 } else { 227 } else {
165 //remove entire entry 228 //remove entire entry
166 - return _popHistory(); 229 + return await _popHistory();
167 } 230 }
168 } 231 }
169 232
170 - Future<GetNavConfig?> popHistory() {  
171 - return SynchronousFuture(_popHistory()); 233 + Future<GetNavConfig?> popHistory() async {
  234 + return await _popHistory();
172 } 235 }
173 236
174 bool _canPopHistory() { 237 bool _canPopHistory() {
175 - return history.length > 1; 238 + return history.length > 0;
176 } 239 }
177 240
178 Future<bool> canPopHistory() { 241 Future<bool> canPopHistory() {
@@ -201,25 +264,30 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -201,25 +264,30 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
201 264
202 /// gets the visual pages from the current history entry 265 /// gets the visual pages from the current history entry
203 /// 266 ///
204 - /// visual pages must have the [RouterOutletContainerMiddleWare] middleware  
205 - /// with `stayAt` equal to the route name of the visual page 267 + /// visual pages must have [participatesInRootNavigator] set to true
206 List<GetPage> getVisualPages() { 268 List<GetPage> getVisualPages() {
207 final currentHistory = currentConfiguration; 269 final currentHistory = currentConfiguration;
208 if (currentHistory == null) return <GetPage>[]; 270 if (currentHistory == null) return <GetPage>[];
209 - return currentHistory.currentTreeBranch.where((r) {  
210 - final mware =  
211 - (r.middlewares ?? []).whereType<RouterOutletContainerMiddleWare>();  
212 - if (mware.length == 0) return true;  
213 - return r.name == mware.first.stayAt;  
214 - }).toList(); 271 +
  272 + final res = currentHistory.currentTreeBranch
  273 + .where((r) => r.participatesInRootNavigator != null);
  274 + if (res.length == 0) {
  275 + //default behavoir, all routes participate in root navigator
  276 + return history.map((e) => e.currentPage!).toList();
  277 + } else {
  278 + //user specified at least one participatesInRootNavigator
  279 + return res
  280 + .where((element) => element.participatesInRootNavigator == true)
  281 + .toList();
  282 + }
215 } 283 }
216 284
217 @override 285 @override
218 Widget build(BuildContext context) { 286 Widget build(BuildContext context) {
219 final pages = getVisualPages(); 287 final pages = getVisualPages();
  288 + if (pages.length == 0) return SizedBox.shrink();
220 final extraObservers = navigatorObservers; 289 final extraObservers = navigatorObservers;
221 return GetNavigator( 290 return GetNavigator(
222 - name: 'root',  
223 key: navigatorKey, 291 key: navigatorKey,
224 onPopPage: _onPopVisualRoute, 292 onPopPage: _onPopVisualRoute,
225 pages: pages, 293 pages: pages,
@@ -232,12 +300,13 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -232,12 +300,13 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
232 ); 300 );
233 } 301 }
234 302
235 - @override  
236 - Future<void> setInitialRoutePath(GetNavConfig configuration) async {  
237 - history.clear();  
238 - _resultCompleter.clear();  
239 - await pushHistory(configuration);  
240 - } 303 + // @override
  304 + // Future<void> setInitialRoutePath(GetNavConfig configuration) async {
  305 + // //no need to clear history with Reorder route strategy
  306 + // // _unsafeHistoryClear();
  307 + // // _resultCompleter.clear();
  308 + // await pushHistory(configuration);
  309 + // }
241 310
242 @override 311 @override
243 Future<void> setNewRoutePath(GetNavConfig configuration) async { 312 Future<void> setNewRoutePath(GetNavConfig configuration) async {
@@ -251,46 +320,56 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -251,46 +320,56 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
251 return route; 320 return route;
252 } 321 }
253 322
254 - Future<T?> toNamed<T>(String fullRoute) {  
255 - final decoder = Get.routeTree.matchRoute(fullRoute);  
256 - return pushHistory<T>( 323 + Future<void> toNamed(
  324 + String page, {
  325 + dynamic arguments,
  326 + Map<String, String>? parameters,
  327 + }) async {
  328 + if (parameters != null) {
  329 + final uri = Uri(path: page, queryParameters: parameters);
  330 + page = uri.toString();
  331 + }
  332 +
  333 + final decoder = Get.routeTree.matchRoute(page, arguments: arguments);
  334 + decoder.replaceArguments(arguments);
  335 +
  336 + await pushHistory(
257 GetNavConfig( 337 GetNavConfig(
258 currentTreeBranch: decoder.treeBranch, 338 currentTreeBranch: decoder.treeBranch,
259 - location: fullRoute, 339 + location: page,
260 state: null, //TODO: persist state? 340 state: null, //TODO: persist state?
261 ), 341 ),
262 ); 342 );
263 } 343 }
264 344
  345 + Future<void> offNamed(
  346 + String page, {
  347 + dynamic arguments,
  348 + Map<String, String>? parameters,
  349 + }) async {
  350 + await popHistory();
  351 + await toNamed(page, arguments: arguments, parameters: parameters);
  352 + }
  353 +
265 /// Removes routes according to [PopMode] 354 /// Removes routes according to [PopMode]
266 /// until it reaches the specifc [fullRoute], 355 /// until it reaches the specifc [fullRoute],
267 /// DOES NOT remove the [fullRoute] 356 /// DOES NOT remove the [fullRoute]
268 - void until( 357 + Future<void> backUntil(
269 String fullRoute, { 358 String fullRoute, {
270 PopMode popMode = PopMode.Page, 359 PopMode popMode = PopMode.Page,
271 - }) { 360 + }) async {
272 // remove history or page entries until you meet route 361 // remove history or page entries until you meet route
273 -  
274 var iterator = currentConfiguration; 362 var iterator = currentConfiguration;
275 while (_canPop(popMode) && 363 while (_canPop(popMode) &&
276 iterator != null && 364 iterator != null &&
277 iterator.location != fullRoute) { 365 iterator.location != fullRoute) {
278 - _pop(popMode); 366 + await _pop(popMode);
279 // replace iterator 367 // replace iterator
280 iterator = currentConfiguration; 368 iterator = currentConfiguration;
281 } 369 }
282 refresh(); 370 refresh();
283 } 371 }
284 372
285 - // GetPage _notFound() {  
286 - // return notFoundRoute ??= GetPage(  
287 - // name: '/404',  
288 - // page: () => Scaffold(  
289 - // body: Text('not found'),  
290 - // ),  
291 - // );  
292 - // }  
293 -  
294 Future<bool> handlePopupRoutes({ 373 Future<bool> handlePopupRoutes({
295 Object? result, 374 Object? result,
296 }) async { 375 }) async {
@@ -313,15 +392,13 @@ class GetDelegate extends RouterDelegate<GetNavConfig> @@ -313,15 +392,13 @@ class GetDelegate extends RouterDelegate<GetNavConfig>
313 //Returning false will cause the entire app to be popped. 392 //Returning false will cause the entire app to be popped.
314 final wasPopup = await handlePopupRoutes(result: result); 393 final wasPopup = await handlePopupRoutes(result: result);
315 if (wasPopup) return true; 394 if (wasPopup) return true;
316 - final _popped = _pop(popMode); 395 + final _popped = await _pop(popMode);
317 refresh(); 396 refresh();
318 if (_popped != null) { 397 if (_popped != null) {
319 //emulate the old pop with result 398 //emulate the old pop with result
320 - final lastCompleter = _resultCompleter.remove(_popped);  
321 - lastCompleter?.complete(result);  
322 - return Future.value(true); 399 + return true;
323 } 400 }
324 - return Future.value(false); 401 + return false;
325 } 402 }
326 403
327 bool _onPopVisualRoute(Route<dynamic> route, dynamic result) { 404 bool _onPopVisualRoute(Route<dynamic> route, dynamic result) {
@@ -350,17 +427,23 @@ class GetNavigator extends Navigator { @@ -350,17 +427,23 @@ class GetNavigator extends Navigator {
350 bool Function(Route<dynamic>, dynamic)? onPopPage, 427 bool Function(Route<dynamic>, dynamic)? onPopPage,
351 required List<Page> pages, 428 required List<Page> pages,
352 List<NavigatorObserver>? observers, 429 List<NavigatorObserver>? observers,
  430 + bool reportsRouteUpdateToEngine = false,
353 TransitionDelegate? transitionDelegate, 431 TransitionDelegate? transitionDelegate,
354 - String? name,  
355 - }) : assert(key != null || name != null,  
356 - 'GetNavigator should either have a key or a name set'),  
357 - super(  
358 - key: key ?? Get.nestedKey(name),  
359 - onPopPage: onPopPage,  
360 - reportsRouteUpdateToEngine: true, 432 + }) : super(
  433 + //keys should be optional
  434 + key: key,
  435 + onPopPage: onPopPage ??
  436 + (route, result) {
  437 + final didPop = route.didPop(result);
  438 + if (!didPop) {
  439 + return false;
  440 + }
  441 + return true;
  442 + },
  443 + reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
361 pages: pages, 444 pages: pages,
362 observers: [ 445 observers: [
363 - GetObserver(), 446 + // GetObserver(),
364 if (observers != null) ...observers, 447 if (observers != null) ...observers,
365 ], 448 ],
366 transitionDelegate: 449 transitionDelegate:
@@ -21,21 +21,21 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object> @@ -21,21 +21,21 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
21 21
22 RouterOutlet({ 22 RouterOutlet({
23 TDelegate? delegate, 23 TDelegate? delegate,
24 - required List<GetPage> Function(T currentNavStack) pickPages, 24 + required Iterable<GetPage> Function(T currentNavStack) pickPages,
25 required Widget Function( 25 required Widget Function(
26 BuildContext context, 26 BuildContext context,
27 TDelegate, 27 TDelegate,
28 - GetPage? page, 28 + Iterable<GetPage>? page,
29 ) 29 )
30 pageBuilder, 30 pageBuilder,
31 }) : this.builder( 31 }) : this.builder(
32 builder: (context, rDelegate, currentConfig) { 32 builder: (context, rDelegate, currentConfig) {
33 - final picked =  
34 - currentConfig == null ? <GetPage>[] : pickPages(currentConfig);  
35 - if (picked.length == 0) {  
36 - return pageBuilder(context, rDelegate, null); 33 + var picked =
  34 + currentConfig == null ? null : pickPages(currentConfig);
  35 + if (picked?.length == 0) {
  36 + picked = null;
37 } 37 }
38 - return pageBuilder(context, rDelegate, picked.last); 38 + return pageBuilder(context, rDelegate, picked);
39 }, 39 },
40 delegate: delegate, 40 delegate: delegate,
41 ); 41 );
@@ -76,65 +76,89 @@ class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object> @@ -76,65 +76,89 @@ class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>
76 } 76 }
77 77
78 class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { 78 class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> {
79 - GetRouterOutlet.builder({  
80 - required Widget Function(  
81 - BuildContext context,  
82 - GetDelegate delegate,  
83 - GetNavConfig? currentRoute,  
84 - )  
85 - builder,  
86 - GetDelegate? routerDelegate,  
87 - }) : super.builder(  
88 - builder: builder,  
89 - delegate: routerDelegate,  
90 - );  
91 -  
92 GetRouterOutlet({ 79 GetRouterOutlet({
  80 + String? anchorRoute,
  81 + required String initialRoute,
  82 + Iterable<GetPage> Function(Iterable<GetPage> afterAnchor)? filterPages,
  83 + GlobalKey<NavigatorState>? key,
  84 + }) : this.pickPages(
  85 + pickPages: (config) {
  86 + Iterable<GetPage<dynamic>> ret;
  87 + if (anchorRoute == null) {
  88 + // jump the ancestor path
  89 + final length = Uri.parse(initialRoute).pathSegments.length;
  90 + return config.currentTreeBranch
  91 + .skip(length)
  92 + .take(length)
  93 + .toList();
  94 + }
  95 + ret = config.currentTreeBranch.pickAfterRoute(anchorRoute);
  96 + if (filterPages != null) {
  97 + ret = filterPages(ret);
  98 + }
  99 + return ret;
  100 + },
  101 + emptyPage: (delegate) =>
  102 + Get.routeTree.matchRoute(initialRoute).route ??
  103 + delegate.notFoundRoute,
  104 + key: key,
  105 + );
  106 + GetRouterOutlet.pickPages({
93 Widget Function(GetDelegate delegate)? emptyWidget, 107 Widget Function(GetDelegate delegate)? emptyWidget,
94 GetPage Function(GetDelegate delegate)? emptyPage, 108 GetPage Function(GetDelegate delegate)? emptyPage,
95 - required List<GetPage> Function(GetNavConfig currentNavStack) pickPages, 109 + required Iterable<GetPage> Function(GetNavConfig currentNavStack) pickPages,
96 bool Function(Route<dynamic>, dynamic)? onPopPage, 110 bool Function(Route<dynamic>, dynamic)? onPopPage,
97 - required String name,  
98 - }) : assert(  
99 - (emptyPage == null && emptyWidget == null) ||  
100 - (emptyPage != null && emptyWidget == null) ||  
101 - (emptyPage == null && emptyWidget != null),  
102 - 'Either use emptyPage or emptyWidget'),  
103 - super(  
104 - pageBuilder: (context, rDelegate, page) {  
105 - var pageRes = page ?? emptyPage?.call(rDelegate);  
106 - if (pageRes != null) { 111 + GlobalKey<NavigatorState>? key,
  112 + }) : super(
  113 + pageBuilder: (context, rDelegate, pages) {
  114 + final pageRes = <GetPage?>[
  115 + ...?pages,
  116 + if (pages == null || pages.length == 0)
  117 + emptyPage?.call(rDelegate),
  118 + ].whereType<GetPage>();
  119 +
  120 + if (pageRes.length > 0) {
107 return GetNavigator( 121 return GetNavigator(
108 onPopPage: onPopPage ?? 122 onPopPage: onPopPage ??
109 - (a, c) { 123 + (route, result) {
  124 + final didPop = route.didPop(result);
  125 + if (!didPop) {
  126 + return false;
  127 + }
110 return true; 128 return true;
111 }, 129 },
112 - pages: [pageRes],  
113 - name: name, 130 + pages: pageRes.toList(),
  131 + key: key,
114 ); 132 );
115 } 133 }
116 return (emptyWidget?.call(rDelegate) ?? SizedBox.shrink()); 134 return (emptyWidget?.call(rDelegate) ?? SizedBox.shrink());
117 }, 135 },
118 pickPages: pickPages, 136 pickPages: pickPages,
119 - delegate: Get.getDelegate(), 137 + delegate: Get.rootDelegate,
120 ); 138 );
121 -}  
122 -  
123 -/// A marker outlet to identify which pages are visual  
124 -/// (handled by the navigator) and which are logical  
125 -/// (handled by the delegate)  
126 -class RouterOutletContainerMiddleWare extends GetMiddleware {  
127 - final String stayAt;  
128 139
129 - RouterOutletContainerMiddleWare(this.stayAt); 140 + GetRouterOutlet.builder({
  141 + required Widget Function(
  142 + BuildContext context,
  143 + GetDelegate delegate,
  144 + GetNavConfig? currentRoute,
  145 + )
  146 + builder,
  147 + GetDelegate? routerDelegate,
  148 + }) : super.builder(
  149 + builder: builder,
  150 + delegate: routerDelegate,
  151 + );
130 } 152 }
131 153
132 extension PagesListExt on List<GetPage> { 154 extension PagesListExt on List<GetPage> {
133 - List<GetPage> pickAtRoute(String route) {  
134 - return skipWhile((value) => value.name != route).toList(); 155 + Iterable<GetPage> pickAtRoute(String route) {
  156 + return skipWhile((value) {
  157 + return value.name != route;
  158 + });
135 } 159 }
136 160
137 - List<GetPage> pickAfterRoute(String route) {  
138 - return skipWhile((value) => value.name != route).skip(1).toList(); 161 + Iterable<GetPage> pickAfterRoute(String route) {
  162 + return pickAtRoute(route).skip(1);
139 } 163 }
140 } 164 }
@@ -118,12 +118,12 @@ class GetCupertinoApp extends StatelessWidget { @@ -118,12 +118,12 @@ class GetCupertinoApp extends StatelessWidget {
118 final BackButtonDispatcher? backButtonDispatcher; 118 final BackButtonDispatcher? backButtonDispatcher;
119 final CupertinoThemeData? theme; 119 final CupertinoThemeData? theme;
120 120
121 - const GetCupertinoApp.router({ 121 + GetCupertinoApp.router({
122 Key? key, 122 Key? key,
123 this.theme, 123 this.theme,
124 this.routeInformationProvider, 124 this.routeInformationProvider,
125 - required RouteInformationParser<Object> this.routeInformationParser,  
126 - required RouterDelegate<Object> this.routerDelegate, 125 + RouteInformationParser<Object>? routeInformationParser,
  126 + RouterDelegate<Object>? routerDelegate,
127 this.backButtonDispatcher, 127 this.backButtonDispatcher,
128 this.builder, 128 this.builder,
129 this.title = '', 129 this.title = '',
@@ -163,7 +163,14 @@ class GetCupertinoApp extends StatelessWidget { @@ -163,7 +163,14 @@ class GetCupertinoApp extends StatelessWidget {
163 this.defaultGlobalState, 163 this.defaultGlobalState,
164 this.getPages, 164 this.getPages,
165 this.unknownRoute, 165 this.unknownRoute,
166 - }) : navigatorObservers = null, 166 + }) : routerDelegate = routerDelegate ??= Get.createDelegate(
  167 + notFoundRoute: unknownRoute,
  168 + ),
  169 + routeInformationParser =
  170 + routeInformationParser ??= Get.createInformationParser(
  171 + initialRoute: getPages?.first.name ?? '/',
  172 + ),
  173 + navigatorObservers = null,
167 navigatorKey = null, 174 navigatorKey = null,
168 onGenerateRoute = null, 175 onGenerateRoute = null,
169 home = null, 176 home = null,
@@ -171,14 +178,23 @@ class GetCupertinoApp extends StatelessWidget { @@ -171,14 +178,23 @@ class GetCupertinoApp extends StatelessWidget {
171 onUnknownRoute = null, 178 onUnknownRoute = null,
172 routes = null, 179 routes = null,
173 initialRoute = null, 180 initialRoute = null,
174 - super(key: key); 181 + super(key: key) {
  182 + Get.routerDelegate = routerDelegate;
  183 + Get.routeInformationParser = routeInformationParser;
  184 + }
175 185
176 Route<dynamic> generator(RouteSettings settings) { 186 Route<dynamic> generator(RouteSettings settings) {
177 - return PageRedirect(settings, unknownRoute).page(); 187 + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
178 } 188 }
179 189
180 - List<Route<dynamic>> initialRoutesGenerate(String name) =>  
181 - [PageRedirect(RouteSettings(name: name), unknownRoute).page()]; 190 + List<Route<dynamic>> initialRoutesGenerate(String name) {
  191 + return [
  192 + PageRedirect(
  193 + settings: RouteSettings(name: name),
  194 + unknownRoute: unknownRoute,
  195 + ).page()
  196 + ];
  197 + }
182 198
183 @override 199 @override
184 Widget build(BuildContext context) => GetBuilder<GetMaterialController>( 200 Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
@@ -203,7 +219,10 @@ class GetCupertinoApp extends StatelessWidget { @@ -203,7 +219,10 @@ class GetCupertinoApp extends StatelessWidget {
203 Get.customTransition = customTransition; 219 Get.customTransition = customTransition;
204 220
205 initialBinding?.dependencies(); 221 initialBinding?.dependencies();
206 - Get.addPages(getPages); 222 + if (getPages != null) {
  223 + Get.addPages(getPages!);
  224 + }
  225 +
207 Get.smartManagement = smartManagement; 226 Get.smartManagement = smartManagement;
208 onInit?.call(); 227 onInit?.call();
209 228
@@ -13,6 +13,7 @@ class GetMaterialApp extends StatelessWidget { @@ -13,6 +13,7 @@ class GetMaterialApp extends StatelessWidget {
13 const GetMaterialApp({ 13 const GetMaterialApp({
14 Key? key, 14 Key? key,
15 this.navigatorKey, 15 this.navigatorKey,
  16 + this.scaffoldMessengerKey,
16 this.home, 17 this.home,
17 Map<String, Widget Function(BuildContext)> this.routes = 18 Map<String, Widget Function(BuildContext)> this.routes =
18 const <String, WidgetBuilder>{}, 19 const <String, WidgetBuilder>{},
@@ -43,6 +44,7 @@ class GetMaterialApp extends StatelessWidget { @@ -43,6 +44,7 @@ class GetMaterialApp extends StatelessWidget {
43 this.showSemanticsDebugger = false, 44 this.showSemanticsDebugger = false,
44 this.debugShowCheckedModeBanner = true, 45 this.debugShowCheckedModeBanner = true,
45 this.shortcuts, 46 this.shortcuts,
  47 + this.scrollBehavior,
46 this.customTransition, 48 this.customTransition,
47 this.translationsKeys, 49 this.translationsKeys,
48 this.translations, 50 this.translations,
@@ -71,6 +73,7 @@ class GetMaterialApp extends StatelessWidget { @@ -71,6 +73,7 @@ class GetMaterialApp extends StatelessWidget {
71 super(key: key); 73 super(key: key);
72 74
73 final GlobalKey<NavigatorState>? navigatorKey; 75 final GlobalKey<NavigatorState>? navigatorKey;
  76 + final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;
74 final Widget? home; 77 final Widget? home;
75 final Map<String, WidgetBuilder>? routes; 78 final Map<String, WidgetBuilder>? routes;
76 final String? initialRoute; 79 final String? initialRoute;
@@ -101,6 +104,7 @@ class GetMaterialApp extends StatelessWidget { @@ -101,6 +104,7 @@ class GetMaterialApp extends StatelessWidget {
101 final bool showSemanticsDebugger; 104 final bool showSemanticsDebugger;
102 final bool debugShowCheckedModeBanner; 105 final bool debugShowCheckedModeBanner;
103 final Map<LogicalKeySet, Intent>? shortcuts; 106 final Map<LogicalKeySet, Intent>? shortcuts;
  107 + final ScrollBehavior? scrollBehavior;
104 final ThemeData? highContrastTheme; 108 final ThemeData? highContrastTheme;
105 final ThemeData? highContrastDarkTheme; 109 final ThemeData? highContrastDarkTheme;
106 final Map<Type, Action<Intent>>? actions; 110 final Map<Type, Action<Intent>>? actions;
@@ -125,11 +129,12 @@ class GetMaterialApp extends StatelessWidget { @@ -125,11 +129,12 @@ class GetMaterialApp extends StatelessWidget {
125 final RouterDelegate<Object>? routerDelegate; 129 final RouterDelegate<Object>? routerDelegate;
126 final BackButtonDispatcher? backButtonDispatcher; 130 final BackButtonDispatcher? backButtonDispatcher;
127 131
128 - const GetMaterialApp.router({ 132 + GetMaterialApp.router({
129 Key? key, 133 Key? key,
130 this.routeInformationProvider, 134 this.routeInformationProvider,
131 - required RouteInformationParser<Object> this.routeInformationParser,  
132 - required RouterDelegate<Object> this.routerDelegate, 135 + this.scaffoldMessengerKey,
  136 + RouteInformationParser<Object>? routeInformationParser,
  137 + RouterDelegate<Object>? routerDelegate,
133 this.backButtonDispatcher, 138 this.backButtonDispatcher,
134 this.builder, 139 this.builder,
135 this.title = '', 140 this.title = '',
@@ -152,6 +157,7 @@ class GetMaterialApp extends StatelessWidget { @@ -152,6 +157,7 @@ class GetMaterialApp extends StatelessWidget {
152 this.showSemanticsDebugger = false, 157 this.showSemanticsDebugger = false,
153 this.debugShowCheckedModeBanner = true, 158 this.debugShowCheckedModeBanner = true,
154 this.shortcuts, 159 this.shortcuts,
  160 + this.scrollBehavior,
155 this.actions, 161 this.actions,
156 this.customTransition, 162 this.customTransition,
157 this.translationsKeys, 163 this.translationsKeys,
@@ -172,8 +178,16 @@ class GetMaterialApp extends StatelessWidget { @@ -172,8 +178,16 @@ class GetMaterialApp extends StatelessWidget {
172 this.transitionDuration, 178 this.transitionDuration,
173 this.defaultGlobalState, 179 this.defaultGlobalState,
174 this.getPages, 180 this.getPages,
  181 + this.navigatorObservers,
175 this.unknownRoute, 182 this.unknownRoute,
176 - }) : navigatorObservers = null, 183 + }) : routerDelegate = routerDelegate ??= Get.createDelegate(
  184 + notFoundRoute: unknownRoute,
  185 + ),
  186 + routeInformationParser =
  187 + routeInformationParser ??= Get.createInformationParser(
  188 + initialRoute: getPages?.first.name ?? '/',
  189 + ),
  190 + //navigatorObservers = null,
177 navigatorKey = null, 191 navigatorKey = null,
178 onGenerateRoute = null, 192 onGenerateRoute = null,
179 home = null, 193 home = null,
@@ -181,13 +195,35 @@ class GetMaterialApp extends StatelessWidget { @@ -181,13 +195,35 @@ class GetMaterialApp extends StatelessWidget {
181 onUnknownRoute = null, 195 onUnknownRoute = null,
182 routes = null, 196 routes = null,
183 initialRoute = null, 197 initialRoute = null,
184 - super(key: key); 198 + super(key: key) {
  199 + Get.routerDelegate = routerDelegate;
  200 + Get.routeInformationParser = routeInformationParser;
  201 + }
  202 +
  203 + Route<dynamic> generator(RouteSettings settings) {
  204 + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
  205 + }
185 206
186 - Route<dynamic> generator(RouteSettings settings) =>  
187 - PageRedirect(settings, unknownRoute).page(); 207 + List<Route<dynamic>> initialRoutesGenerate(String name) {
  208 + return [
  209 + PageRedirect(
  210 + settings: RouteSettings(name: name),
  211 + unknownRoute: unknownRoute,
  212 + ).page()
  213 + ];
  214 + }
188 215
189 - List<Route<dynamic>> initialRoutesGenerate(String name) =>  
190 - [PageRedirect(RouteSettings(name: name), unknownRoute).page()]; 216 + Widget defaultBuilder(BuildContext context, Widget? child) {
  217 + return Directionality(
  218 + textDirection: textDirection ??
  219 + (rtlLanguages.contains(Get.locale?.languageCode)
  220 + ? TextDirection.rtl
  221 + : TextDirection.ltr),
  222 + child: builder == null
  223 + ? (child ?? SizedBox.shrink())
  224 + : builder!(context, child),
  225 + );
  226 + }
191 227
192 @override 228 @override
193 Widget build(BuildContext context) => GetBuilder<GetMaterialController>( 229 Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
@@ -212,8 +248,11 @@ class GetMaterialApp extends StatelessWidget { @@ -212,8 +248,11 @@ class GetMaterialApp extends StatelessWidget {
212 Get.customTransition = customTransition; 248 Get.customTransition = customTransition;
213 249
214 initialBinding?.dependencies(); 250 initialBinding?.dependencies();
215 - Get.addPages(getPages);  
216 - Get.setDefaultDelegate(routerDelegate); 251 + if (getPages != null) {
  252 + Get.addPages(getPages!);
  253 + }
  254 +
  255 + //Get.setDefaultDelegate(routerDelegate);
217 Get.smartManagement = smartManagement; 256 Get.smartManagement = smartManagement;
218 onInit?.call(); 257 onInit?.call();
219 258
@@ -231,18 +270,11 @@ class GetMaterialApp extends StatelessWidget { @@ -231,18 +270,11 @@ class GetMaterialApp extends StatelessWidget {
231 ? MaterialApp.router( 270 ? MaterialApp.router(
232 routerDelegate: routerDelegate!, 271 routerDelegate: routerDelegate!,
233 routeInformationParser: routeInformationParser!, 272 routeInformationParser: routeInformationParser!,
  273 + scaffoldMessengerKey: scaffoldMessengerKey,
234 backButtonDispatcher: backButtonDispatcher, 274 backButtonDispatcher: backButtonDispatcher,
235 routeInformationProvider: routeInformationProvider, 275 routeInformationProvider: routeInformationProvider,
236 key: _.unikey, 276 key: _.unikey,
237 - builder: (context, child) {  
238 - return Directionality(  
239 - textDirection: textDirection ??  
240 - (rtlLanguages.contains(Get.locale?.languageCode)  
241 - ? TextDirection.rtl  
242 - : TextDirection.ltr),  
243 - child: builder == null ? child! : builder!(context, child),  
244 - );  
245 - }, 277 + builder: defaultBuilder,
246 title: title, 278 title: title,
247 onGenerateTitle: onGenerateTitle, 279 onGenerateTitle: onGenerateTitle,
248 color: color, 280 color: color,
@@ -262,11 +294,13 @@ class GetMaterialApp extends StatelessWidget { @@ -262,11 +294,13 @@ class GetMaterialApp extends StatelessWidget {
262 showSemanticsDebugger: showSemanticsDebugger, 294 showSemanticsDebugger: showSemanticsDebugger,
263 debugShowCheckedModeBanner: debugShowCheckedModeBanner, 295 debugShowCheckedModeBanner: debugShowCheckedModeBanner,
264 shortcuts: shortcuts, 296 shortcuts: shortcuts,
  297 + scrollBehavior: scrollBehavior,
265 ) 298 )
266 : MaterialApp( 299 : MaterialApp(
267 key: _.unikey, 300 key: _.unikey,
268 navigatorKey: 301 navigatorKey:
269 (navigatorKey == null ? Get.key : Get.addKey(navigatorKey!)), 302 (navigatorKey == null ? Get.key : Get.addKey(navigatorKey!)),
  303 + scaffoldMessengerKey: scaffoldMessengerKey,
270 home: home, 304 home: home,
271 routes: routes ?? const <String, WidgetBuilder>{}, 305 routes: routes ?? const <String, WidgetBuilder>{},
272 initialRoute: initialRoute, 306 initialRoute: initialRoute,
@@ -283,15 +317,7 @@ class GetMaterialApp extends StatelessWidget { @@ -283,15 +317,7 @@ class GetMaterialApp extends StatelessWidget {
283 GetObserver(routingCallback, Get.routing) 317 GetObserver(routingCallback, Get.routing)
284 ] 318 ]
285 ..addAll(navigatorObservers!)), 319 ..addAll(navigatorObservers!)),
286 - builder: (context, child) {  
287 - return Directionality(  
288 - textDirection: textDirection ??  
289 - (rtlLanguages.contains(Get.locale?.languageCode)  
290 - ? TextDirection.rtl  
291 - : TextDirection.ltr),  
292 - child: builder == null ? child! : builder!(context, child),  
293 - );  
294 - }, 320 + builder: defaultBuilder,
295 title: title, 321 title: title,
296 onGenerateTitle: onGenerateTitle, 322 onGenerateTitle: onGenerateTitle,
297 color: color, 323 color: color,
@@ -311,6 +337,7 @@ class GetMaterialApp extends StatelessWidget { @@ -311,6 +337,7 @@ class GetMaterialApp extends StatelessWidget {
311 showSemanticsDebugger: showSemanticsDebugger, 337 showSemanticsDebugger: showSemanticsDebugger,
312 debugShowCheckedModeBanner: debugShowCheckedModeBanner, 338 debugShowCheckedModeBanner: debugShowCheckedModeBanner,
313 shortcuts: shortcuts, 339 shortcuts: shortcuts,
  340 + scrollBehavior: scrollBehavior,
314 // actions: actions, 341 // actions: actions,
315 )); 342 ));
316 } 343 }
@@ -5,10 +5,27 @@ class RouteDecoder { @@ -5,10 +5,27 @@ class RouteDecoder {
5 final List<GetPage> treeBranch; 5 final List<GetPage> treeBranch;
6 GetPage? get route => treeBranch.isEmpty ? null : treeBranch.last; 6 GetPage? get route => treeBranch.isEmpty ? null : treeBranch.last;
7 final Map<String, String> parameters; 7 final Map<String, String> parameters;
  8 + final Object? arguments;
8 const RouteDecoder( 9 const RouteDecoder(
9 this.treeBranch, 10 this.treeBranch,
10 this.parameters, 11 this.parameters,
  12 + this.arguments,
11 ); 13 );
  14 + void replaceArguments(Object? arguments) {
  15 + final _route = route;
  16 + if (_route != null) {
  17 + final index = treeBranch.indexOf(_route);
  18 + treeBranch[index] = _route.copy(arguments: arguments);
  19 + }
  20 + }
  21 +
  22 + void replaceParameters(Object? arguments) {
  23 + final _route = route;
  24 + if (_route != null) {
  25 + final index = treeBranch.indexOf(_route);
  26 + treeBranch[index] = _route.copy(parameters: parameters);
  27 + }
  28 + }
12 } 29 }
13 30
14 class ParseRouteTree { 31 class ParseRouteTree {
@@ -18,7 +35,7 @@ class ParseRouteTree { @@ -18,7 +35,7 @@ class ParseRouteTree {
18 35
19 final List<GetPage> routes; 36 final List<GetPage> routes;
20 37
21 - RouteDecoder matchRoute(String name) { 38 + RouteDecoder matchRoute(String name, {Object? arguments}) {
22 final uri = Uri.parse(name); 39 final uri = Uri.parse(name);
23 // /home/profile/123 => home,profile,123 => /,/home,/home/profile,/home/profile/123 40 // /home/profile/123 => home,profile,123 => /,/home,/home/profile,/home/profile/123
24 final split = uri.path.split('/').where((element) => element.isNotEmpty); 41 final split = uri.path.split('/').where((element) => element.isNotEmpty);
@@ -53,8 +70,8 @@ class ParseRouteTree { @@ -53,8 +70,8 @@ class ParseRouteTree {
53 final mappedTreeBranch = treeBranch 70 final mappedTreeBranch = treeBranch
54 .map( 71 .map(
55 (e) => e.value.copy( 72 (e) => e.value.copy(
56 - parameter: {  
57 - if (e.value.parameter != null) ...e.value.parameter!, 73 + parameters: {
  74 + if (e.value.parameters != null) ...e.value.parameters!,
58 ...params, 75 ...params,
59 }, 76 },
60 name: e.key, 77 name: e.key,
@@ -64,6 +81,7 @@ class ParseRouteTree { @@ -64,6 +81,7 @@ class ParseRouteTree {
64 return RouteDecoder( 81 return RouteDecoder(
65 mappedTreeBranch, 82 mappedTreeBranch,
66 params, 83 params,
  84 + arguments,
67 ); 85 );
68 } 86 }
69 87
@@ -71,6 +89,7 @@ class ParseRouteTree { @@ -71,6 +89,7 @@ class ParseRouteTree {
71 return RouteDecoder( 89 return RouteDecoder(
72 treeBranch.map((e) => e.value).toList(), 90 treeBranch.map((e) => e.value).toList(),
73 params, 91 params,
  92 + arguments,
74 ); 93 );
75 } 94 }
76 95
@@ -91,21 +110,35 @@ class ParseRouteTree { @@ -91,21 +110,35 @@ class ParseRouteTree {
91 110
92 List<GetPage> _flattenPage(GetPage route) { 111 List<GetPage> _flattenPage(GetPage route) {
93 final result = <GetPage>[]; 112 final result = <GetPage>[];
94 - if (route.children == null || route.children!.isEmpty) { 113 + if (route.children.isEmpty) {
95 return result; 114 return result;
96 } 115 }
97 116
98 final parentPath = route.name; 117 final parentPath = route.name;
99 - for (var page in route.children!) { 118 + for (var page in route.children) {
100 // Add Parent middlewares to children 119 // Add Parent middlewares to children
101 - final pageMiddlewares = page.middlewares ?? <GetMiddleware>[];  
102 - pageMiddlewares.addAll(route.middlewares ?? <GetMiddleware>[]);  
103 - result.add(_addChild(page, parentPath, pageMiddlewares)); 120 + final parentMiddlewares = [
  121 + if (page.middlewares != null) ...page.middlewares!,
  122 + if (route.middlewares != null) ...route.middlewares!
  123 + ];
  124 + result.add(
  125 + _addChild(
  126 + page,
  127 + parentPath,
  128 + parentMiddlewares,
  129 + ),
  130 + );
104 131
105 final children = _flattenPage(page); 132 final children = _flattenPage(page);
106 for (var child in children) { 133 for (var child in children) {
107 - pageMiddlewares.addAll(child.middlewares ?? <GetMiddleware>[]);  
108 - result.add(_addChild(child, parentPath, pageMiddlewares)); 134 + result.add(_addChild(
  135 + child,
  136 + parentPath,
  137 + [
  138 + ...parentMiddlewares,
  139 + if (child.middlewares != null) ...child.middlewares!,
  140 + ],
  141 + ));
109 } 142 }
110 } 143 }
111 return result; 144 return result;
@@ -114,24 +147,9 @@ class ParseRouteTree { @@ -114,24 +147,9 @@ class ParseRouteTree {
114 /// Change the Path for a [GetPage] 147 /// Change the Path for a [GetPage]
115 GetPage _addChild( 148 GetPage _addChild(
116 GetPage origin, String parentPath, List<GetMiddleware> middlewares) => 149 GetPage origin, String parentPath, List<GetMiddleware> middlewares) =>
117 - GetPage(  
118 - name: (parentPath + origin.name).replaceAll(r'//', '/'),  
119 - page: origin.page,  
120 - title: origin.title,  
121 - alignment: origin.alignment,  
122 - transition: origin.transition,  
123 - binding: origin.binding,  
124 - bindings: origin.bindings,  
125 - curve: origin.curve,  
126 - customTransition: origin.customTransition,  
127 - fullscreenDialog: origin.fullscreenDialog,  
128 - maintainState: origin.maintainState,  
129 - opaque: origin.opaque,  
130 - parameter: origin.parameter,  
131 - popGesture: origin.popGesture,  
132 - preventDuplicates: origin.preventDuplicates,  
133 - transitionDuration: origin.transitionDuration, 150 + origin.copy(
134 middlewares: middlewares, 151 middlewares: middlewares,
  152 + name: (parentPath + origin.name).replaceAll(r'//', '/'),
135 ); 153 );
136 154
137 GetPage? _findRoute(String name) { 155 GetPage? _findRoute(String name) {
@@ -4,7 +4,6 @@ import '../../../get_utils/get_utils.dart'; @@ -4,7 +4,6 @@ import '../../../get_utils/get_utils.dart';
4 import '../routes/custom_transition.dart'; 4 import '../routes/custom_transition.dart';
5 import '../routes/observers/route_observer.dart'; 5 import '../routes/observers/route_observer.dart';
6 import '../routes/transitions_type.dart'; 6 import '../routes/transitions_type.dart';
7 -import 'parse_route.dart';  
8 7
9 class GetMaterialController extends GetxController { 8 class GetMaterialController extends GetxController {
10 bool testMode = false; 9 bool testMode = false;
@@ -28,11 +27,16 @@ class GetMaterialController extends GetxController { @@ -28,11 +27,16 @@ class GetMaterialController extends GetxController {
28 27
29 Map<String, String?> parameters = {}; 28 Map<String, String?> parameters = {};
30 29
31 - late ParseRouteTree routeTree;  
32 -  
33 CustomTransition? customTransition; 30 CustomTransition? customTransition;
34 31
35 - GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>(); 32 + var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default');
  33 +
  34 + GlobalKey<NavigatorState> get key => _key;
  35 +
  36 + GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
  37 + _key = newKey;
  38 + return key;
  39 + }
36 40
37 Map<dynamic, GlobalKey<NavigatorState>> keys = {}; 41 Map<dynamic, GlobalKey<NavigatorState>> keys = {};
38 42
1 -import 'dart:math';  
2 -import 'dart:ui' show lerpDouble;  
3 -import 'package:flutter/cupertino.dart';  
4 -import 'package:flutter/gestures.dart';  
5 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
6 -import '../../../get_core/get_core.dart';  
7 -import '../../../get_instance/get_instance.dart';  
8 -import '../../get_navigation.dart'; 2 +
  3 +import '../../../get.dart';
9 import 'custom_transition.dart'; 4 import 'custom_transition.dart';
10 -import 'default_transitions.dart'; 5 +import 'get_transition_mixin.dart';
  6 +import 'route_middleware.dart';
11 import 'transitions_type.dart'; 7 import 'transitions_type.dart';
12 8
13 -class GetPageRoute<T> extends PageRoute<T> { 9 +class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> {
  10 + /// Creates a page route for use in an iOS designed app.
  11 + ///
  12 + /// The [builder], [maintainState], and [fullscreenDialog] arguments must not
  13 + /// be null.
14 GetPageRoute({ 14 GetPageRoute({
15 RouteSettings? settings, 15 RouteSettings? settings,
16 this.transitionDuration = const Duration(milliseconds: 300), 16 this.transitionDuration = const Duration(milliseconds: 300),
17 this.opaque = true, 17 this.opaque = true,
18 this.parameter, 18 this.parameter,
  19 + this.gestureWidth = 20.0,
19 this.curve, 20 this.curve,
20 this.alignment, 21 this.alignment,
21 this.transition, 22 this.transition,
@@ -27,6 +28,7 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -27,6 +28,7 @@ class GetPageRoute<T> extends PageRoute<T> {
27 this.bindings, 28 this.bindings,
28 this.routeName, 29 this.routeName,
29 this.page, 30 this.page,
  31 + this.title,
30 this.barrierLabel, 32 this.barrierLabel,
31 this.maintainState = true, 33 this.maintainState = true,
32 bool fullscreenDialog = false, 34 bool fullscreenDialog = false,
@@ -36,35 +38,23 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -36,35 +38,23 @@ class GetPageRoute<T> extends PageRoute<T> {
36 38
37 @override 39 @override
38 final Duration transitionDuration; 40 final Duration transitionDuration;
39 -  
40 final GetPageBuilder? page; 41 final GetPageBuilder? page;
41 -  
42 final String? routeName; 42 final String? routeName;
43 -  
44 final String reference; 43 final String reference;
45 -  
46 final CustomTransition? customTransition; 44 final CustomTransition? customTransition;
47 -  
48 final Bindings? binding; 45 final Bindings? binding;
49 -  
50 final Map<String, String>? parameter; 46 final Map<String, String>? parameter;
51 -  
52 final List<Bindings>? bindings; 47 final List<Bindings>? bindings;
53 48
54 @override 49 @override
55 final bool opaque; 50 final bool opaque;
56 -  
57 final bool? popGesture; 51 final bool? popGesture;
58 52
59 @override 53 @override
60 final bool barrierDismissible; 54 final bool barrierDismissible;
61 -  
62 final Transition? transition; 55 final Transition? transition;
63 -  
64 final Curve? curve; 56 final Curve? curve;
65 -  
66 final Alignment? alignment; 57 final Alignment? alignment;
67 -  
68 final List<GetMiddleware>? middlewares; 58 final List<GetMiddleware>? middlewares;
69 59
70 @override 60 @override
@@ -77,308 +67,6 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -77,308 +67,6 @@ class GetPageRoute<T> extends PageRoute<T> {
77 final bool maintainState; 67 final bool maintainState;
78 68
79 @override 69 @override
80 - bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {  
81 - // Don't perform outgoing animation if the next route is a  
82 - // fullscreen dialog.  
83 - return nextRoute is PageRoute && !nextRoute.fullscreenDialog;  
84 - }  
85 -  
86 - static bool _isPopGestureEnabled<T>(PageRoute<T> route) {  
87 - // ignore: lines_longer_than_80_chars  
88 - if (route.isFirst ||  
89 - route.willHandlePopInternally ||  
90 - route.hasScopedWillPopCallback ||  
91 - route.fullscreenDialog ||  
92 - route.animation!.status != AnimationStatus.completed ||  
93 - route.secondaryAnimation!.status != AnimationStatus.dismissed ||  
94 - isPopGestureInProgress(route)) return false;  
95 -  
96 - return true;  
97 - }  
98 -  
99 - static _CupertinoBackGestureController<T> _startPopGesture<T>(  
100 - PageRoute<T> route) {  
101 - assert(_isPopGestureEnabled(route));  
102 -  
103 - return _CupertinoBackGestureController<T>(  
104 - navigator: route.navigator!,  
105 - controller: route.controller!,  
106 - );  
107 - }  
108 -  
109 - @override  
110 - Widget buildPage(  
111 - BuildContext? context,  
112 - Animation<double>? animation,  
113 - Animation<double>? secondaryAnimation,  
114 - ) {  
115 - // Get.reference = settings.name ?? routeName;  
116 - Get.reference = reference;  
117 -  
118 - final middlewareRunner = MiddlewareRunner(middlewares);  
119 - final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings);  
120 -  
121 - binding?.dependencies();  
122 - if (bindingsToBind != null) {  
123 - for (final binding in bindingsToBind) {  
124 - binding.dependencies();  
125 - }  
126 - }  
127 -  
128 - final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!;  
129 - return middlewareRunner.runOnPageBuilt(pageToBuild());  
130 - }  
131 -  
132 - static bool isPopGestureInProgress(PageRoute<dynamic> route) {  
133 - return route.navigator!.userGestureInProgress;  
134 - }  
135 -  
136 - bool get popGestureInProgress => isPopGestureInProgress(this);  
137 -  
138 - @override  
139 - Widget buildTransitions(BuildContext context, Animation<double> animation,  
140 - Animation<double> secondaryAnimation, Widget child) {  
141 - final finalCurve = curve ?? Get.defaultTransitionCurve;  
142 - final hasCurve = curve != null;  
143 - if (fullscreenDialog && transition == null) {  
144 - /// by default, if no curve is defined, use Cupertino transition in the  
145 - /// default way (no linearTransition)... otherwise take the curve passed.  
146 - return CupertinoFullscreenDialogTransition(  
147 - primaryRouteAnimation: hasCurve  
148 - ? CurvedAnimation(parent: animation, curve: finalCurve)  
149 - : animation,  
150 - secondaryRouteAnimation: secondaryAnimation,  
151 - child: child,  
152 - linearTransition: hasCurve);  
153 - }  
154 - if (customTransition != null) {  
155 - return customTransition!.buildTransition(  
156 - context,  
157 - finalCurve,  
158 - alignment,  
159 - animation,  
160 - secondaryAnimation,  
161 - popGesture ?? Get.defaultPopGesture  
162 - ? _CupertinoBackGestureDetector<T>(  
163 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
164 - onStartPopGesture: () => _startPopGesture<T>(this),  
165 - child: child)  
166 - : child,  
167 - );  
168 - }  
169 -  
170 - /// Apply the curve by default...  
171 - final iosAnimation = animation;  
172 - animation = CurvedAnimation(parent: animation, curve: finalCurve);  
173 -  
174 - switch (transition ?? Get.defaultTransition) {  
175 - case Transition.leftToRight:  
176 - return SlideLeftTransition().buildTransitions(  
177 - context,  
178 - curve,  
179 - alignment,  
180 - animation,  
181 - secondaryAnimation,  
182 - popGesture ?? Get.defaultPopGesture  
183 - ? _CupertinoBackGestureDetector<T>(  
184 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
185 - onStartPopGesture: () => _startPopGesture<T>(this),  
186 - child: child)  
187 - : child);  
188 -  
189 - case Transition.downToUp:  
190 - return SlideDownTransition().buildTransitions(  
191 - context,  
192 - curve,  
193 - alignment,  
194 - animation,  
195 - secondaryAnimation,  
196 - popGesture ?? Get.defaultPopGesture  
197 - ? _CupertinoBackGestureDetector<T>(  
198 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
199 - onStartPopGesture: () => _startPopGesture<T>(this),  
200 - child: child)  
201 - : child);  
202 -  
203 - case Transition.upToDown:  
204 - return SlideTopTransition().buildTransitions(  
205 - context,  
206 - curve,  
207 - alignment,  
208 - animation,  
209 - secondaryAnimation,  
210 - popGesture ?? Get.defaultPopGesture  
211 - ? _CupertinoBackGestureDetector<T>(  
212 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
213 - onStartPopGesture: () => _startPopGesture<T>(this),  
214 - child: child)  
215 - : child);  
216 -  
217 - case Transition.noTransition:  
218 - return popGesture ?? Get.defaultPopGesture  
219 - ? _CupertinoBackGestureDetector<T>(  
220 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
221 - onStartPopGesture: () => _startPopGesture<T>(this),  
222 - child: child)  
223 - : child;  
224 -  
225 - case Transition.rightToLeft:  
226 - return SlideRightTransition().buildTransitions(  
227 - context,  
228 - curve,  
229 - alignment,  
230 - animation,  
231 - secondaryAnimation,  
232 - popGesture ?? Get.defaultPopGesture  
233 - ? _CupertinoBackGestureDetector<T>(  
234 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
235 - onStartPopGesture: () => _startPopGesture<T>(this),  
236 - child: child)  
237 - : child);  
238 -  
239 - case Transition.zoom:  
240 - return ZoomInTransition().buildTransitions(  
241 - context,  
242 - curve,  
243 - alignment,  
244 - animation,  
245 - secondaryAnimation,  
246 - popGesture ?? Get.defaultPopGesture  
247 - ? _CupertinoBackGestureDetector<T>(  
248 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
249 - onStartPopGesture: () => _startPopGesture<T>(this),  
250 - child: child)  
251 - : child);  
252 -  
253 - case Transition.fadeIn:  
254 - return FadeInTransition().buildTransitions(  
255 - context,  
256 - curve,  
257 - alignment,  
258 - animation,  
259 - secondaryAnimation,  
260 - popGesture ?? Get.defaultPopGesture  
261 - ? _CupertinoBackGestureDetector<T>(  
262 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
263 - onStartPopGesture: () => _startPopGesture<T>(this),  
264 - child: child)  
265 - : child);  
266 -  
267 - case Transition.rightToLeftWithFade:  
268 - return RightToLeftFadeTransition().buildTransitions(  
269 - context,  
270 - curve,  
271 - alignment,  
272 - animation,  
273 - secondaryAnimation,  
274 - popGesture ?? Get.defaultPopGesture  
275 - ? _CupertinoBackGestureDetector<T>(  
276 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
277 - onStartPopGesture: () => _startPopGesture<T>(this),  
278 - child: child)  
279 - : child);  
280 -  
281 - case Transition.leftToRightWithFade:  
282 - return LeftToRightFadeTransition().buildTransitions(  
283 - context,  
284 - curve,  
285 - alignment,  
286 - animation,  
287 - secondaryAnimation,  
288 - popGesture ?? Get.defaultPopGesture  
289 - ? _CupertinoBackGestureDetector<T>(  
290 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
291 - onStartPopGesture: () => _startPopGesture<T>(this),  
292 - child: child)  
293 - : child);  
294 -  
295 - case Transition.cupertino:  
296 - return CupertinoPageTransitionsBuilder().buildTransitions(  
297 - this,  
298 - context,  
299 - iosAnimation,  
300 - secondaryAnimation,  
301 - popGesture ?? Get.defaultPopGesture  
302 - ? _CupertinoBackGestureDetector<T>(  
303 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
304 - onStartPopGesture: () => _startPopGesture<T>(this),  
305 - child: child)  
306 - : child);  
307 -  
308 - case Transition.size:  
309 - return SizeTransitions().buildTransitions(  
310 - context,  
311 - curve!,  
312 - alignment,  
313 - animation,  
314 - secondaryAnimation,  
315 - popGesture ?? Get.defaultPopGesture  
316 - ? _CupertinoBackGestureDetector<T>(  
317 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
318 - onStartPopGesture: () => _startPopGesture<T>(this),  
319 - child: child)  
320 - : child);  
321 -  
322 - case Transition.fade:  
323 - return FadeUpwardsPageTransitionsBuilder().buildTransitions(  
324 - this,  
325 - context,  
326 - animation,  
327 - secondaryAnimation,  
328 - popGesture ?? Get.defaultPopGesture  
329 - ? _CupertinoBackGestureDetector<T>(  
330 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
331 - onStartPopGesture: () => _startPopGesture<T>(this),  
332 - child: child)  
333 - : child);  
334 -  
335 - case Transition.topLevel:  
336 - return ZoomPageTransitionsBuilder().buildTransitions(  
337 - this,  
338 - context,  
339 - animation,  
340 - secondaryAnimation,  
341 - popGesture ?? Get.defaultPopGesture  
342 - ? _CupertinoBackGestureDetector<T>(  
343 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
344 - onStartPopGesture: () => _startPopGesture<T>(this),  
345 - child: child)  
346 - : child);  
347 -  
348 - case Transition.native:  
349 - return PageTransitionsTheme().buildTransitions(  
350 - this,  
351 - context,  
352 - iosAnimation,  
353 - secondaryAnimation,  
354 - popGesture ?? Get.defaultPopGesture  
355 - ? _CupertinoBackGestureDetector<T>(  
356 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
357 - onStartPopGesture: () => _startPopGesture<T>(this),  
358 - child: child)  
359 - : child);  
360 -  
361 - default:  
362 - if (Get.customTransition != null) {  
363 - return Get.customTransition!.buildTransition(  
364 - context, curve, alignment, animation, secondaryAnimation, child);  
365 - }  
366 -  
367 - return PageTransitionsTheme().buildTransitions(  
368 - this,  
369 - context,  
370 - iosAnimation,  
371 - secondaryAnimation,  
372 - popGesture ?? Get.defaultPopGesture  
373 - ? _CupertinoBackGestureDetector<T>(  
374 - enabledCallback: () => _isPopGestureEnabled<T>(this),  
375 - onStartPopGesture: () => _startPopGesture<T>(this),  
376 - child: child)  
377 - : child);  
378 - }  
379 - }  
380 -  
381 - @override  
382 void dispose() { 70 void dispose() {
383 super.dispose(); 71 super.dispose();
384 if (Get.smartManagement != SmartManagement.onlyBuilder) { 72 if (Get.smartManagement != SmartManagement.onlyBuilder) {
@@ -396,220 +84,30 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -396,220 +84,30 @@ class GetPageRoute<T> extends PageRoute<T> {
396 final middlewareRunner = MiddlewareRunner(middlewares); 84 final middlewareRunner = MiddlewareRunner(middlewares);
397 middlewareRunner.runOnPageDispose(); 85 middlewareRunner.runOnPageDispose();
398 } 86 }
399 -}  
400 -  
401 -const double _kBackGestureWidth = 20.0;  
402 -const double _kMinFlingVelocity = 1.0;  
403 -const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.  
404 -  
405 -// The maximum time for a page to get reset to it's original position if the  
406 -// user releases a page mid swipe.  
407 -const int _kMaxPageBackAnimationTime = 300;  
408 -  
409 -class _CupertinoBackGestureDetector<T> extends StatefulWidget {  
410 - const _CupertinoBackGestureDetector({  
411 - Key? key,  
412 - required this.enabledCallback,  
413 - required this.onStartPopGesture,  
414 - required this.child,  
415 - }) : super(key: key);  
416 -  
417 - final Widget child;  
418 -  
419 - final ValueGetter<bool> enabledCallback;  
420 -  
421 - final ValueGetter<_CupertinoBackGestureController<T>> onStartPopGesture;  
422 87
423 @override 88 @override
424 - _CupertinoBackGestureDetectorState<T> createState() =>  
425 - _CupertinoBackGestureDetectorState<T>();  
426 -}  
427 -  
428 -class _CupertinoBackGestureDetectorState<T>  
429 - extends State<_CupertinoBackGestureDetector<T>> {  
430 - _CupertinoBackGestureController<T>? _backGestureController; 89 + Widget buildContent(BuildContext context) {
  90 + Get.reference = reference;
  91 + final middlewareRunner = MiddlewareRunner(middlewares);
  92 + final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings);
431 93
432 - late HorizontalDragGestureRecognizer _recognizer; 94 + binding?.dependencies();
  95 + if (bindingsToBind != null) {
  96 + for (final binding in bindingsToBind) {
  97 + binding.dependencies();
  98 + }
  99 + }
433 100
434 - @override  
435 - void initState() {  
436 - super.initState();  
437 - _recognizer = HorizontalDragGestureRecognizer(debugOwner: this)  
438 - ..onStart = _handleDragStart  
439 - ..onUpdate = _handleDragUpdate  
440 - ..onEnd = _handleDragEnd  
441 - ..onCancel = _handleDragCancel; 101 + final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!;
  102 + return middlewareRunner.runOnPageBuilt(pageToBuild());
442 } 103 }
443 104
444 @override 105 @override
445 - void dispose() {  
446 - _recognizer.dispose();  
447 - super.dispose();  
448 - }  
449 -  
450 - void _handleDragStart(DragStartDetails details) {  
451 - assert(mounted);  
452 - assert(_backGestureController == null);  
453 - _backGestureController = widget.onStartPopGesture();  
454 - }  
455 -  
456 - void _handleDragUpdate(DragUpdateDetails details) {  
457 - assert(mounted);  
458 - assert(_backGestureController != null);  
459 - _backGestureController!.dragUpdate(  
460 - _convertToLogical(details.primaryDelta! / context.size!.width)!);  
461 - }  
462 -  
463 - void _handleDragEnd(DragEndDetails details) {  
464 - assert(mounted);  
465 - assert(_backGestureController != null);  
466 - _backGestureController!.dragEnd(_convertToLogical(  
467 - details.velocity.pixelsPerSecond.dx / context.size!.width)!);  
468 - _backGestureController = null;  
469 - }  
470 -  
471 - void _handleDragCancel() {  
472 - assert(mounted);  
473 - // This can be called even if start is not called, paired with  
474 - // the "down" event that we don't consider here.  
475 - _backGestureController?.dragEnd(0.0);  
476 - _backGestureController = null;  
477 - }  
478 -  
479 - void _handlePointerDown(PointerDownEvent event) {  
480 - if (widget.enabledCallback()) _recognizer.addPointer(event);  
481 - }  
482 -  
483 - double? _convertToLogical(double value) {  
484 - switch (Directionality.of(context)) {  
485 - case TextDirection.rtl:  
486 - return -value;  
487 - case TextDirection.ltr:  
488 - return value;  
489 - default:  
490 - return value;  
491 - }  
492 - } 106 + final String? title;
493 107
494 @override 108 @override
495 - Widget build(BuildContext context) {  
496 - assert(debugCheckHasDirectionality(context));  
497 - // For devices with notches, the drag area needs to be larger on the side  
498 - // that has the notch.  
499 - var dragAreaWidth = Directionality.of(context) == TextDirection.ltr  
500 - ? MediaQuery.of(context).padding.left  
501 - : MediaQuery.of(context).padding.right;  
502 - dragAreaWidth = max(dragAreaWidth, _kBackGestureWidth);  
503 - return Stack(  
504 - fit: StackFit.passthrough,  
505 - children: <Widget>[  
506 - widget.child,  
507 - PositionedDirectional(  
508 - start: 0.0,  
509 - width: dragAreaWidth,  
510 - top: 0.0,  
511 - bottom: 0.0,  
512 - child: Listener(  
513 - onPointerDown: _handlePointerDown,  
514 - behavior: HitTestBehavior.translucent,  
515 - ),  
516 - ),  
517 - ],  
518 - );  
519 - }  
520 -}  
521 -  
522 -class _CupertinoBackGestureController<T> {  
523 - /// Creates a controller for an iOS-style back gesture.  
524 - ///  
525 - /// The [navigator] and [controller] arguments must not be null.  
526 - _CupertinoBackGestureController({  
527 - required this.navigator,  
528 - required this.controller,  
529 - }) {  
530 - navigator.didStartUserGesture();  
531 - }  
532 -  
533 - final AnimationController controller;  
534 - final NavigatorState navigator;  
535 -  
536 - /// The drag gesture has changed by [fractionalDelta]. The total range of the  
537 - /// drag should be 0.0 to 1.0.  
538 - void dragUpdate(double delta) {  
539 - controller.value -= delta;  
540 - }  
541 -  
542 - /// The drag gesture has ended with a horizontal motion of  
543 - /// [fractionalVelocity] as a fraction of screen width per second.  
544 - void dragEnd(double velocity) {  
545 - // Fling in the appropriate direction.  
546 - // AnimationController.fling is guaranteed to  
547 - // take at least one frame.  
548 - //  
549 - // This curve has been determined through rigorously eyeballing native iOS  
550 - // animations.  
551 - const Curve animationCurve = Curves.fastLinearToSlowEaseIn;  
552 - bool animateForward;  
553 -  
554 - // If the user releases the page before mid screen with sufficient velocity,  
555 - // or after mid screen, we should animate the page out. Otherwise, the page  
556 - // should be animated back in.  
557 - if (velocity.abs() >= _kMinFlingVelocity) {  
558 - animateForward = velocity <= 0;  
559 - } else {  
560 - animateForward = controller.value > 0.5;  
561 - } 109 + String get debugLabel => '${super.debugLabel}(${settings.name})';
562 110
563 - if (animateForward) {  
564 - // The closer the panel is to dismissing, the shorter the animation is.  
565 - // We want to cap the animation time, but we want to use a linear curve  
566 - // to determine it.  
567 - final droppedPageForwardAnimationTime = min(  
568 - lerpDouble(  
569 - _kMaxDroppedSwipePageForwardAnimationTime,  
570 - 0,  
571 - controller.value,  
572 - )!  
573 - .floor(),  
574 - _kMaxPageBackAnimationTime,  
575 - );  
576 - controller.animateTo(1.0,  
577 - duration: Duration(milliseconds: droppedPageForwardAnimationTime),  
578 - curve: animationCurve);  
579 - } else {  
580 - // This route is destined to pop at this point. Reuse navigator's pop.  
581 - navigator.pop();  
582 -  
583 - // The popping may have finished inline if already at the target  
584 - // destination.  
585 - if (controller.isAnimating) {  
586 - // Otherwise, use a custom popping animation duration and curve.  
587 - final droppedPageBackAnimationTime = lerpDouble(  
588 - 0,  
589 - _kMaxDroppedSwipePageForwardAnimationTime,  
590 - controller.value,  
591 - )!  
592 - .floor();  
593 - controller.animateBack(  
594 - 0.0,  
595 - duration: Duration(milliseconds: droppedPageBackAnimationTime),  
596 - curve: animationCurve,  
597 - );  
598 - }  
599 - }  
600 -  
601 - if (controller.isAnimating) {  
602 - // Keep the userGestureInProgress in true state so we don't change the  
603 - // curve of the page transition mid-flight since CupertinoPageTransition  
604 - // depends on userGestureInProgress.  
605 - late AnimationStatusListener animationStatusCallback;  
606 - animationStatusCallback = (status) {  
607 - navigator.didStopUserGesture();  
608 - controller.removeStatusListener(animationStatusCallback);  
609 - };  
610 - controller.addStatusListener(animationStatusCallback);  
611 - } else {  
612 - navigator.didStopUserGesture();  
613 - }  
614 - } 111 + @override
  112 + final double gestureWidth;
615 } 113 }
  1 +import 'package:flutter/cupertino.dart';
1 import 'package:flutter/foundation.dart'; 2 import 'package:flutter/foundation.dart';
2 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
3 import 'package:flutter/widgets.dart'; 4 import 'package:flutter/widgets.dart';
@@ -29,13 +30,15 @@ class PathDecoded { @@ -29,13 +30,15 @@ class PathDecoded {
29 class GetPage<T> extends Page<T> { 30 class GetPage<T> extends Page<T> {
30 final GetPageBuilder page; 31 final GetPageBuilder page;
31 final bool? popGesture; 32 final bool? popGesture;
32 - final Map<String, String>? parameter; 33 + final Map<String, String>? parameters;
33 final String? title; 34 final String? title;
34 final Transition? transition; 35 final Transition? transition;
35 final Curve curve; 36 final Curve curve;
  37 + final bool? participatesInRootNavigator;
36 final Alignment? alignment; 38 final Alignment? alignment;
37 final bool maintainState; 39 final bool maintainState;
38 final bool opaque; 40 final bool opaque;
  41 + final double gestureWidth;
39 final Bindings? binding; 42 final Bindings? binding;
40 final List<Bindings> bindings; 43 final List<Bindings> bindings;
41 final CustomTransition? customTransition; 44 final CustomTransition? customTransition;
@@ -49,12 +52,12 @@ class GetPage<T> extends Page<T> { @@ -49,12 +52,12 @@ class GetPage<T> extends Page<T> {
49 // RouteSettings get settings => this; 52 // RouteSettings get settings => this;
50 53
51 @override 54 @override
52 - Object? get arguments => Get.arguments; 55 + final Object? arguments;
53 56
54 @override 57 @override
55 final String name; 58 final String name;
56 59
57 - final List<GetPage>? children; 60 + final List<GetPage> children;
58 final List<GetMiddleware>? middlewares; 61 final List<GetMiddleware>? middlewares;
59 final PathDecoded path; 62 final PathDecoded path;
60 final GetPage? unknownRoute; 63 final GetPage? unknownRoute;
@@ -63,11 +66,13 @@ class GetPage<T> extends Page<T> { @@ -63,11 +66,13 @@ class GetPage<T> extends Page<T> {
63 required this.name, 66 required this.name,
64 required this.page, 67 required this.page,
65 this.title, 68 this.title,
  69 + this.participatesInRootNavigator,
  70 + this.gestureWidth = 20,
66 // RouteSettings settings, 71 // RouteSettings settings,
67 this.maintainState = true, 72 this.maintainState = true,
68 this.curve = Curves.linear, 73 this.curve = Curves.linear,
69 this.alignment, 74 this.alignment,
70 - this.parameter, 75 + this.parameters,
71 this.opaque = true, 76 this.opaque = true,
72 this.transitionDuration, 77 this.transitionDuration,
73 this.popGesture, 78 this.popGesture,
@@ -76,10 +81,11 @@ class GetPage<T> extends Page<T> { @@ -76,10 +81,11 @@ class GetPage<T> extends Page<T> {
76 this.transition, 81 this.transition,
77 this.customTransition, 82 this.customTransition,
78 this.fullscreenDialog = false, 83 this.fullscreenDialog = false,
79 - this.children, 84 + this.children = const <GetPage>[],
80 this.middlewares, 85 this.middlewares,
81 this.unknownRoute, 86 this.unknownRoute,
82 - this.preventDuplicates = false, 87 + this.arguments,
  88 + this.preventDuplicates = true,
83 }) : path = _nameToRegex(name), 89 }) : path = _nameToRegex(name),
84 super( 90 super(
85 key: ValueKey(name), 91 key: ValueKey(name),
@@ -109,11 +115,11 @@ class GetPage<T> extends Page<T> { @@ -109,11 +115,11 @@ class GetPage<T> extends Page<T> {
109 return PathDecoded(RegExp('^$stringPath\$'), keys); 115 return PathDecoded(RegExp('^$stringPath\$'), keys);
110 } 116 }
111 117
112 - GetPage copy({ 118 + GetPage<T> copy({
113 String? name, 119 String? name,
114 GetPageBuilder? page, 120 GetPageBuilder? page,
115 bool? popGesture, 121 bool? popGesture,
116 - Map<String, String>? parameter, 122 + Map<String, String>? parameters,
117 String? title, 123 String? title,
118 Transition? transition, 124 Transition? transition,
119 Curve? curve, 125 Curve? curve,
@@ -130,13 +136,18 @@ class GetPage<T> extends Page<T> { @@ -130,13 +136,18 @@ class GetPage<T> extends Page<T> {
130 GetPage? unknownRoute, 136 GetPage? unknownRoute,
131 List<GetMiddleware>? middlewares, 137 List<GetMiddleware>? middlewares,
132 bool? preventDuplicates, 138 bool? preventDuplicates,
  139 + double? gestureWidth,
  140 + bool? participatesInRootNavigator,
  141 + Object? arguments,
133 }) { 142 }) {
134 return GetPage( 143 return GetPage(
  144 + participatesInRootNavigator:
  145 + participatesInRootNavigator ?? this.participatesInRootNavigator,
135 preventDuplicates: preventDuplicates ?? this.preventDuplicates, 146 preventDuplicates: preventDuplicates ?? this.preventDuplicates,
136 name: name ?? this.name, 147 name: name ?? this.name,
137 page: page ?? this.page, 148 page: page ?? this.page,
138 popGesture: popGesture ?? this.popGesture, 149 popGesture: popGesture ?? this.popGesture,
139 - parameter: parameter ?? this.parameter, 150 + parameters: parameters ?? this.parameters,
140 title: title ?? this.title, 151 title: title ?? this.title,
141 transition: transition ?? this.transition, 152 transition: transition ?? this.transition,
142 curve: curve ?? this.curve, 153 curve: curve ?? this.curve,
@@ -151,14 +162,18 @@ class GetPage<T> extends Page<T> { @@ -151,14 +162,18 @@ class GetPage<T> extends Page<T> {
151 children: children ?? this.children, 162 children: children ?? this.children,
152 unknownRoute: unknownRoute ?? this.unknownRoute, 163 unknownRoute: unknownRoute ?? this.unknownRoute,
153 middlewares: middlewares ?? this.middlewares, 164 middlewares: middlewares ?? this.middlewares,
  165 + gestureWidth: gestureWidth ?? this.gestureWidth,
  166 + arguments: arguments ?? this.arguments,
154 ); 167 );
155 } 168 }
156 169
157 @override 170 @override
158 Route<T> createRoute(BuildContext context) { 171 Route<T> createRoute(BuildContext context) {
  172 + // return GetPageRoute<T>(settings: this, page: page);
159 return PageRedirect( 173 return PageRedirect(
160 - this,  
161 - unknownRoute,  
162 - ).page<T>(); 174 + route: this,
  175 + settings: this,
  176 + unknownRoute: unknownRoute,
  177 + ).getPageToRoute<T>(this, unknownRoute);
163 } 178 }
164 } 179 }
  1 +import 'dart:math';
  2 +import 'dart:ui';
  3 +
  4 +import 'package:flutter/cupertino.dart';
  5 +import 'package:flutter/foundation.dart';
  6 +import 'package:flutter/gestures.dart';
  7 +import 'package:flutter/material.dart';
  8 +import '../../../get.dart';
  9 +
  10 +import 'default_transitions.dart';
  11 +import 'transitions_type.dart';
  12 +
  13 +//const double _kBackGestureWidth = 20.0;
  14 +const double _kMinFlingVelocity = 1.0; // Screen widths per second.
  15 +
  16 +// An eyeballed value for the maximum time it takes
  17 +//for a page to animate forward
  18 +// if the user releases a page mid swipe.
  19 +const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.
  20 +
  21 +// The maximum time for a page to get reset to it's original position if the
  22 +// user releases a page mid swipe.
  23 +const int _kMaxPageBackAnimationTime = 300; // Milliseconds.
  24 +
  25 +mixin GetPageRouteTransitionMixin<T> on PageRoute<T> {
  26 + /// Builds the primary contents of the route.
  27 + @protected
  28 + Widget buildContent(BuildContext context);
  29 +
  30 + /// {@template flutter.cupertino.CupertinoRouteTransitionMixin.title}
  31 + /// A title string for this route.
  32 + ///
  33 + /// Used to auto-populate [CupertinoNavigationBar] and
  34 + /// [CupertinoSliverNavigationBar]'s `middle`/`largeTitle` widgets when
  35 + /// one is not manually supplied.
  36 + /// {@endtemplate}
  37 + String? get title;
  38 +
  39 + double get gestureWidth;
  40 +
  41 + ValueNotifier<String?>? _previousTitle;
  42 +
  43 + /// The title string of the previous [CupertinoPageRoute].
  44 + ///
  45 + /// The [ValueListenable]'s value is readable after the route is installed
  46 + /// onto a [Navigator]. The [ValueListenable] will also notify its listeners
  47 + /// if the value changes (such as by replacing the previous route).
  48 + ///
  49 + /// The [ValueListenable] itself will be null before the route is installed.
  50 + /// Its content value will be null if the previous route has no title or
  51 + /// is not a [CupertinoPageRoute].
  52 + ///
  53 + /// See also:
  54 + ///
  55 + /// * [ValueListenableBuilder], which can be used to listen and rebuild
  56 + /// widgets based on a ValueListenable.
  57 + ValueListenable<String?> get previousTitle {
  58 + assert(
  59 + _previousTitle != null,
  60 + '''
  61 +Cannot read the previousTitle for a route that has not yet been installed''',
  62 + );
  63 + return _previousTitle!;
  64 + }
  65 +
  66 + @override
  67 + void didChangePrevious(Route<dynamic>? previousRoute) {
  68 + final previousTitleString = previousRoute is CupertinoRouteTransitionMixin
  69 + ? previousRoute.title
  70 + : null;
  71 + if (_previousTitle == null) {
  72 + _previousTitle = ValueNotifier<String?>(previousTitleString);
  73 + } else {
  74 + _previousTitle!.value = previousTitleString;
  75 + }
  76 + super.didChangePrevious(previousRoute);
  77 + }
  78 +
  79 + @override
  80 + // A relatively rigorous eyeball estimation.
  81 + Duration get transitionDuration => const Duration(milliseconds: 400);
  82 +
  83 + @override
  84 + Color? get barrierColor => null;
  85 +
  86 + @override
  87 + String? get barrierLabel => null;
  88 +
  89 + @override
  90 + bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {
  91 + // Don't perform outgoing animation if the next route is a
  92 + // fullscreen dialog.
  93 + return nextRoute is CupertinoRouteTransitionMixin &&
  94 + !nextRoute.fullscreenDialog;
  95 + }
  96 +
  97 + /// True if an iOS-style back swipe pop gesture is currently
  98 + /// underway for [route].
  99 + ///
  100 + /// This just check the route's [NavigatorState.userGestureInProgress].
  101 + ///
  102 + /// See also:
  103 + ///
  104 + /// * [popGestureEnabled], which returns true if a user-triggered pop gesture
  105 + /// would be allowed.
  106 + static bool isPopGestureInProgress(PageRoute<dynamic> route) {
  107 + return route.navigator!.userGestureInProgress;
  108 + }
  109 +
  110 + /// True if an iOS-style back swipe pop gesture is currently
  111 + /// underway for this route.
  112 + ///
  113 + /// See also:
  114 + ///
  115 + /// * [isPopGestureInProgress], which returns true if a Cupertino pop gesture
  116 + /// is currently underway for specific route.
  117 + /// * [popGestureEnabled], which returns true if a user-triggered pop gesture
  118 + /// would be allowed.
  119 + bool get popGestureInProgress => isPopGestureInProgress(this);
  120 +
  121 + /// Whether a pop gesture can be started by the user.
  122 + ///
  123 + /// Returns true if the user can edge-swipe to a previous route.
  124 + ///
  125 + /// Returns false once [isPopGestureInProgress] is true, but
  126 + /// [isPopGestureInProgress] can only become true if [popGestureEnabled] was
  127 + /// true first.
  128 + ///
  129 + /// This should only be used between frames, not during build.
  130 + bool get popGestureEnabled => _isPopGestureEnabled(this);
  131 +
  132 + static bool _isPopGestureEnabled<T>(PageRoute<T> route) {
  133 + // If there's nothing to go back to, then obviously we don't support
  134 + // the back gesture.
  135 + if (route.isFirst) return false;
  136 + // If the route wouldn't actually pop if we popped it, then the gesture
  137 + // would be really confusing (or would skip internal routes),
  138 + //so disallow it.
  139 + if (route.willHandlePopInternally) return false;
  140 + // If attempts to dismiss this route might be vetoed such as in a page
  141 + // with forms, then do not allow the user to dismiss the route with a swipe.
  142 + if (route.hasScopedWillPopCallback) return false;
  143 + // Fullscreen dialogs aren't dismissible by back swipe.
  144 + if (route.fullscreenDialog) return false;
  145 + // If we're in an animation already, we cannot be manually swiped.
  146 + if (route.animation!.status != AnimationStatus.completed) return false;
  147 + // If we're being popped into, we also cannot be swiped until the pop above
  148 + // it completes. This translates to our secondary animation being
  149 + // dismissed.
  150 + if (route.secondaryAnimation!.status != AnimationStatus.dismissed) {
  151 + return false;
  152 + }
  153 + // If we're in a gesture already, we cannot start another.
  154 + if (isPopGestureInProgress(route)) return false;
  155 +
  156 + // Looks like a back gesture would be welcome!
  157 + return true;
  158 + }
  159 +
  160 + @override
  161 + Widget buildPage(BuildContext context, Animation<double> animation,
  162 + Animation<double> secondaryAnimation) {
  163 + final child = buildContent(context);
  164 + final Widget result = Semantics(
  165 + scopesRoute: true,
  166 + explicitChildNodes: true,
  167 + child: child,
  168 + );
  169 + return result;
  170 + }
  171 +
  172 + // Called by CupertinoBackGestureDetector when a pop ("back") drag start
  173 + // gesture is detected. The returned controller handles all of the subsequent
  174 + // drag events.
  175 + static CupertinoBackGestureController<T> _startPopGesture<T>(
  176 + PageRoute<T> route) {
  177 + assert(_isPopGestureEnabled(route));
  178 +
  179 + return CupertinoBackGestureController<T>(
  180 + navigator: route.navigator!,
  181 + controller: route.controller!, // protected access
  182 + );
  183 + }
  184 +
  185 + /// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full
  186 + /// screen dialog, otherwise a [CupertinoPageTransition] is returned.
  187 + ///
  188 + /// Used by [CupertinoPageRoute.buildTransitions].
  189 + ///
  190 + /// This method can be applied to any [PageRoute], not just
  191 + /// [CupertinoPageRoute]. It's typically used to provide a Cupertino style
  192 + /// horizontal transition for material widgets when the target platform
  193 + /// is [TargetPlatform.iOS].
  194 + ///
  195 + /// See also:
  196 + ///
  197 + /// * [CupertinoPageTransitionsBuilder], which uses this method to define a
  198 + /// [PageTransitionsBuilder] for the [PageTransitionsTheme].
  199 + static Widget buildPageTransitions<T>(
  200 + PageRoute<T> rawRoute,
  201 + BuildContext context,
  202 + Animation<double> animation,
  203 + Animation<double> secondaryAnimation,
  204 + Widget child,
  205 + ) {
  206 + // Check if the route has an animation that's currently participating
  207 + // in a back swipe gesture.
  208 + //
  209 + // In the middle of a back gesture drag, let the transition be linear to
  210 + // match finger motions.
  211 + final route = rawRoute as GetPageRoute<T>;
  212 + final linearTransition = isPopGestureInProgress(route);
  213 + final finalCurve = route.curve ?? Get.defaultTransitionCurve;
  214 + final hasCurve = route.curve != null;
  215 + if (route.fullscreenDialog && route.transition == null) {
  216 + return CupertinoFullscreenDialogTransition(
  217 + primaryRouteAnimation: hasCurve
  218 + ? CurvedAnimation(parent: animation, curve: finalCurve)
  219 + : animation,
  220 + secondaryRouteAnimation: secondaryAnimation,
  221 + child: child,
  222 + linearTransition: linearTransition,
  223 + );
  224 + } else {
  225 + if (route.customTransition != null) {
  226 + return route.customTransition!.buildTransition(
  227 + context,
  228 + finalCurve,
  229 + route.alignment,
  230 + animation,
  231 + secondaryAnimation,
  232 + route.popGesture ?? Get.defaultPopGesture
  233 + ? CupertinoBackGestureDetector<T>(
  234 + gestureWidth: route.gestureWidth,
  235 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  236 + onStartPopGesture: () => _startPopGesture<T>(route),
  237 + child: child)
  238 + : child,
  239 + );
  240 + }
  241 +
  242 + /// Apply the curve by default...
  243 + final iosAnimation = animation;
  244 + animation = CurvedAnimation(parent: animation, curve: finalCurve);
  245 +
  246 + switch (route.transition ?? Get.defaultTransition) {
  247 + case Transition.leftToRight:
  248 + return SlideLeftTransition().buildTransitions(
  249 + context,
  250 + route.curve,
  251 + route.alignment,
  252 + animation,
  253 + secondaryAnimation,
  254 + route.popGesture ?? Get.defaultPopGesture
  255 + ? CupertinoBackGestureDetector<T>(
  256 + gestureWidth: route.gestureWidth,
  257 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  258 + onStartPopGesture: () => _startPopGesture<T>(route),
  259 + child: child)
  260 + : child);
  261 +
  262 + case Transition.downToUp:
  263 + return SlideDownTransition().buildTransitions(
  264 + context,
  265 + route.curve,
  266 + route.alignment,
  267 + animation,
  268 + secondaryAnimation,
  269 + route.popGesture ?? Get.defaultPopGesture
  270 + ? CupertinoBackGestureDetector<T>(
  271 + gestureWidth: route.gestureWidth,
  272 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  273 + onStartPopGesture: () => _startPopGesture<T>(route),
  274 + child: child)
  275 + : child);
  276 +
  277 + case Transition.upToDown:
  278 + return SlideTopTransition().buildTransitions(
  279 + context,
  280 + route.curve,
  281 + route.alignment,
  282 + animation,
  283 + secondaryAnimation,
  284 + route.popGesture ?? Get.defaultPopGesture
  285 + ? CupertinoBackGestureDetector<T>(
  286 + gestureWidth: route.gestureWidth,
  287 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  288 + onStartPopGesture: () => _startPopGesture<T>(route),
  289 + child: child)
  290 + : child);
  291 +
  292 + case Transition.noTransition:
  293 + return route.popGesture ?? Get.defaultPopGesture
  294 + ? CupertinoBackGestureDetector<T>(
  295 + gestureWidth: route.gestureWidth,
  296 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  297 + onStartPopGesture: () => _startPopGesture<T>(route),
  298 + child: child)
  299 + : child;
  300 +
  301 + case Transition.rightToLeft:
  302 + return SlideRightTransition().buildTransitions(
  303 + context,
  304 + route.curve,
  305 + route.alignment,
  306 + animation,
  307 + secondaryAnimation,
  308 + route.popGesture ?? Get.defaultPopGesture
  309 + ? CupertinoBackGestureDetector<T>(
  310 + gestureWidth: route.gestureWidth,
  311 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  312 + onStartPopGesture: () => _startPopGesture<T>(route),
  313 + child: child)
  314 + : child);
  315 +
  316 + case Transition.zoom:
  317 + return ZoomInTransition().buildTransitions(
  318 + context,
  319 + route.curve,
  320 + route.alignment,
  321 + animation,
  322 + secondaryAnimation,
  323 + route.popGesture ?? Get.defaultPopGesture
  324 + ? CupertinoBackGestureDetector<T>(
  325 + gestureWidth: route.gestureWidth,
  326 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  327 + onStartPopGesture: () => _startPopGesture<T>(route),
  328 + child: child)
  329 + : child);
  330 +
  331 + case Transition.fadeIn:
  332 + return FadeInTransition().buildTransitions(
  333 + context,
  334 + route.curve,
  335 + route.alignment,
  336 + animation,
  337 + secondaryAnimation,
  338 + route.popGesture ?? Get.defaultPopGesture
  339 + ? CupertinoBackGestureDetector<T>(
  340 + gestureWidth: route.gestureWidth,
  341 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  342 + onStartPopGesture: () => _startPopGesture<T>(route),
  343 + child: child)
  344 + : child);
  345 +
  346 + case Transition.rightToLeftWithFade:
  347 + return RightToLeftFadeTransition().buildTransitions(
  348 + context,
  349 + route.curve,
  350 + route.alignment,
  351 + animation,
  352 + secondaryAnimation,
  353 + route.popGesture ?? Get.defaultPopGesture
  354 + ? CupertinoBackGestureDetector<T>(
  355 + gestureWidth: route.gestureWidth,
  356 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  357 + onStartPopGesture: () => _startPopGesture<T>(route),
  358 + child: child)
  359 + : child);
  360 +
  361 + case Transition.leftToRightWithFade:
  362 + return LeftToRightFadeTransition().buildTransitions(
  363 + context,
  364 + route.curve,
  365 + route.alignment,
  366 + animation,
  367 + secondaryAnimation,
  368 + route.popGesture ?? Get.defaultPopGesture
  369 + ? CupertinoBackGestureDetector<T>(
  370 + gestureWidth: route.gestureWidth,
  371 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  372 + onStartPopGesture: () => _startPopGesture<T>(route),
  373 + child: child)
  374 + : child);
  375 +
  376 + case Transition.cupertino:
  377 + return CupertinoPageTransition(
  378 + primaryRouteAnimation: animation,
  379 + secondaryRouteAnimation: secondaryAnimation,
  380 + linearTransition: linearTransition,
  381 + child: CupertinoBackGestureDetector<T>(
  382 + gestureWidth: route.gestureWidth,
  383 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  384 + onStartPopGesture: () => _startPopGesture<T>(route),
  385 + child: child,
  386 + ),
  387 + );
  388 +
  389 + case Transition.size:
  390 + return SizeTransitions().buildTransitions(
  391 + context,
  392 + route.curve!,
  393 + route.alignment,
  394 + animation,
  395 + secondaryAnimation,
  396 + route.popGesture ?? Get.defaultPopGesture
  397 + ? CupertinoBackGestureDetector<T>(
  398 + gestureWidth: route.gestureWidth,
  399 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  400 + onStartPopGesture: () => _startPopGesture<T>(route),
  401 + child: child)
  402 + : child);
  403 +
  404 + case Transition.fade:
  405 + return FadeUpwardsPageTransitionsBuilder().buildTransitions(
  406 + route,
  407 + context,
  408 + animation,
  409 + secondaryAnimation,
  410 + route.popGesture ?? Get.defaultPopGesture
  411 + ? CupertinoBackGestureDetector<T>(
  412 + gestureWidth: route.gestureWidth,
  413 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  414 + onStartPopGesture: () => _startPopGesture<T>(route),
  415 + child: child)
  416 + : child);
  417 +
  418 + case Transition.topLevel:
  419 + return ZoomPageTransitionsBuilder().buildTransitions(
  420 + route,
  421 + context,
  422 + animation,
  423 + secondaryAnimation,
  424 + route.popGesture ?? Get.defaultPopGesture
  425 + ? CupertinoBackGestureDetector<T>(
  426 + gestureWidth: route.gestureWidth,
  427 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  428 + onStartPopGesture: () => _startPopGesture<T>(route),
  429 + child: child)
  430 + : child);
  431 +
  432 + case Transition.native:
  433 + return PageTransitionsTheme().buildTransitions(
  434 + route,
  435 + context,
  436 + iosAnimation,
  437 + secondaryAnimation,
  438 + route.popGesture ?? Get.defaultPopGesture
  439 + ? CupertinoBackGestureDetector<T>(
  440 + gestureWidth: route.gestureWidth,
  441 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  442 + onStartPopGesture: () => _startPopGesture<T>(route),
  443 + child: child)
  444 + : child);
  445 +
  446 + default:
  447 + if (Get.customTransition != null) {
  448 + return Get.customTransition!.buildTransition(context, route.curve,
  449 + route.alignment, animation, secondaryAnimation, child);
  450 + }
  451 +
  452 + return PageTransitionsTheme().buildTransitions(
  453 + route,
  454 + context,
  455 + iosAnimation,
  456 + secondaryAnimation,
  457 + route.popGesture ?? Get.defaultPopGesture
  458 + ? CupertinoBackGestureDetector<T>(
  459 + gestureWidth: route.gestureWidth,
  460 + enabledCallback: () => _isPopGestureEnabled<T>(route),
  461 + onStartPopGesture: () => _startPopGesture<T>(route),
  462 + child: child)
  463 + : child);
  464 + }
  465 + }
  466 + }
  467 +
  468 + @override
  469 + Widget buildTransitions(BuildContext context, Animation<double> animation,
  470 + Animation<double> secondaryAnimation, Widget child) {
  471 + return buildPageTransitions<T>(
  472 + this, context, animation, secondaryAnimation, child);
  473 + }
  474 +}
  475 +
  476 +class CupertinoBackGestureDetector<T> extends StatefulWidget {
  477 + const CupertinoBackGestureDetector({
  478 + Key? key,
  479 + required this.enabledCallback,
  480 + required this.onStartPopGesture,
  481 + required this.child,
  482 + required this.gestureWidth,
  483 + }) : super(key: key);
  484 +
  485 + final Widget child;
  486 + final double gestureWidth;
  487 +
  488 + final ValueGetter<bool> enabledCallback;
  489 +
  490 + final ValueGetter<CupertinoBackGestureController<T>> onStartPopGesture;
  491 +
  492 + @override
  493 + CupertinoBackGestureDetectorState<T> createState() =>
  494 + CupertinoBackGestureDetectorState<T>();
  495 +}
  496 +
  497 +class CupertinoBackGestureDetectorState<T>
  498 + extends State<CupertinoBackGestureDetector<T>> {
  499 + CupertinoBackGestureController<T>? _backGestureController;
  500 +
  501 + late HorizontalDragGestureRecognizer _recognizer;
  502 +
  503 + @override
  504 + void initState() {
  505 + super.initState();
  506 + _recognizer = HorizontalDragGestureRecognizer(debugOwner: this)
  507 + ..onStart = _handleDragStart
  508 + ..onUpdate = _handleDragUpdate
  509 + ..onEnd = _handleDragEnd
  510 + ..onCancel = _handleDragCancel;
  511 + }
  512 +
  513 + @override
  514 + void dispose() {
  515 + _recognizer.dispose();
  516 + super.dispose();
  517 + }
  518 +
  519 + void _handleDragStart(DragStartDetails details) {
  520 + assert(mounted);
  521 + assert(_backGestureController == null);
  522 + _backGestureController = widget.onStartPopGesture();
  523 + }
  524 +
  525 + void _handleDragUpdate(DragUpdateDetails details) {
  526 + assert(mounted);
  527 + assert(_backGestureController != null);
  528 + _backGestureController!.dragUpdate(
  529 + _convertToLogical(details.primaryDelta! / context.size!.width));
  530 + }
  531 +
  532 + void _handleDragEnd(DragEndDetails details) {
  533 + assert(mounted);
  534 + assert(_backGestureController != null);
  535 + _backGestureController!.dragEnd(_convertToLogical(
  536 + details.velocity.pixelsPerSecond.dx / context.size!.width));
  537 + _backGestureController = null;
  538 + }
  539 +
  540 + void _handleDragCancel() {
  541 + assert(mounted);
  542 + // This can be called even if start is not called, paired with
  543 + // the "down" event
  544 + // that we don't consider here.
  545 + _backGestureController?.dragEnd(0.0);
  546 + _backGestureController = null;
  547 + }
  548 +
  549 + void _handlePointerDown(PointerDownEvent event) {
  550 + if (widget.enabledCallback()) _recognizer.addPointer(event);
  551 + }
  552 +
  553 + double _convertToLogical(double value) {
  554 + switch (Directionality.of(context)) {
  555 + case TextDirection.rtl:
  556 + return -value;
  557 + case TextDirection.ltr:
  558 + return value;
  559 + }
  560 + }
  561 +
  562 + @override
  563 + Widget build(BuildContext context) {
  564 + assert(debugCheckHasDirectionality(context));
  565 + // For devices with notches, the drag area needs to be larger on the side
  566 + // that has the notch.
  567 + var dragAreaWidth = Directionality.of(context) == TextDirection.ltr
  568 + ? MediaQuery.of(context).padding.left
  569 + : MediaQuery.of(context).padding.right;
  570 + dragAreaWidth = max(dragAreaWidth, widget.gestureWidth);
  571 + return Stack(
  572 + fit: StackFit.passthrough,
  573 + children: <Widget>[
  574 + widget.child,
  575 + PositionedDirectional(
  576 + start: 0.0,
  577 + width: dragAreaWidth,
  578 + top: 0.0,
  579 + bottom: 0.0,
  580 + child: Listener(
  581 + onPointerDown: _handlePointerDown,
  582 + behavior: HitTestBehavior.translucent,
  583 + ),
  584 + ),
  585 + ],
  586 + );
  587 + }
  588 +}
  589 +
  590 +class CupertinoBackGestureController<T> {
  591 + /// Creates a controller for an iOS-style back gesture.
  592 + ///
  593 + /// The [navigator] and [controller] arguments must not be null.
  594 + CupertinoBackGestureController({
  595 + required this.navigator,
  596 + required this.controller,
  597 + }) {
  598 + navigator.didStartUserGesture();
  599 + }
  600 +
  601 + final AnimationController controller;
  602 + final NavigatorState navigator;
  603 +
  604 + /// The drag gesture has changed by [fractionalDelta]. The total range of the
  605 + /// drag should be 0.0 to 1.0.
  606 + void dragUpdate(double delta) {
  607 + controller.value -= delta;
  608 + }
  609 +
  610 + /// The drag gesture has ended with a horizontal motion of
  611 + /// [fractionalVelocity] as a fraction of screen width per second.
  612 + void dragEnd(double velocity) {
  613 + // Fling in the appropriate direction.
  614 + // AnimationController.fling is guaranteed to
  615 + // take at least one frame.
  616 + //
  617 + // This curve has been determined through rigorously eyeballing native iOS
  618 + // animations.
  619 + const Curve animationCurve = Curves.fastLinearToSlowEaseIn;
  620 + final bool animateForward;
  621 +
  622 + // If the user releases the page before mid screen with sufficient velocity,
  623 + // or after mid screen, we should animate the page out. Otherwise, the page
  624 + // should be animated back in.
  625 + if (velocity.abs() >= _kMinFlingVelocity) {
  626 + animateForward = velocity <= 0;
  627 + } else {
  628 + animateForward = controller.value > 0.5;
  629 + }
  630 +
  631 + if (animateForward) {
  632 + // The closer the panel is to dismissing, the shorter the animation is.
  633 + // We want to cap the animation time, but we want to use a linear curve
  634 + // to determine it.
  635 + final droppedPageForwardAnimationTime = min(
  636 + lerpDouble(
  637 + _kMaxDroppedSwipePageForwardAnimationTime, 0, controller.value)!
  638 + .floor(),
  639 + _kMaxPageBackAnimationTime,
  640 + );
  641 + controller.animateTo(1.0,
  642 + duration: Duration(milliseconds: droppedPageForwardAnimationTime),
  643 + curve: animationCurve);
  644 + } else {
  645 + // This route is destined to pop at this point. Reuse navigator's pop.
  646 + navigator.pop();
  647 +
  648 + // The popping may have finished inline if already at the
  649 + // target destination.
  650 + if (controller.isAnimating) {
  651 + // Otherwise, use a custom popping animation duration and curve.
  652 + final droppedPageBackAnimationTime = lerpDouble(
  653 + 0, _kMaxDroppedSwipePageForwardAnimationTime, controller.value)!
  654 + .floor();
  655 + controller.animateBack(0.0,
  656 + duration: Duration(milliseconds: droppedPageBackAnimationTime),
  657 + curve: animationCurve);
  658 + }
  659 + }
  660 +
  661 + if (controller.isAnimating) {
  662 + // Keep the userGestureInProgress in true state so we don't change the
  663 + // curve of the page transition mid-flight since CupertinoPageTransition
  664 + // depends on userGestureInProgress.
  665 + late AnimationStatusListener animationStatusCallback;
  666 + animationStatusCallback = (status) {
  667 + navigator.didStopUserGesture();
  668 + controller.removeStatusListener(animationStatusCallback);
  669 + };
  670 + controller.addStatusListener(animationStatusCallback);
  671 + } else {
  672 + navigator.didStopUserGesture();
  673 + }
  674 + }
  675 +}