Committed by
GitHub
Merge pull request #2145 from jonataslaw/refactor-nav
Refactor nav
Showing
57 changed files
with
1877 additions
and
1094 deletions
@@ -14,11 +14,11 @@ class MyApp extends StatelessWidget { | @@ -14,11 +14,11 @@ class MyApp extends StatelessWidget { | ||
14 | 14 | ||
15 | @override | 15 | @override |
16 | Widget build(BuildContext context) { | 16 | Widget build(BuildContext context) { |
17 | - return GetMaterialApp.router( | 17 | + return GetMaterialApp( |
18 | debugShowCheckedModeBanner: false, | 18 | debugShowCheckedModeBanner: false, |
19 | enableLog: true, | 19 | enableLog: true, |
20 | logWriterCallback: Logger.write, | 20 | logWriterCallback: Logger.write, |
21 | - // initialRoute: AppPages.INITIAL, | 21 | + initialRoute: AppPages.INITIAL, |
22 | getPages: AppPages.routes, | 22 | getPages: AppPages.routes, |
23 | locale: TranslationService.locale, | 23 | locale: TranslationService.locale, |
24 | fallbackLocale: TranslationService.fallbackLocale, | 24 | fallbackLocale: TranslationService.fallbackLocale, |
@@ -5,13 +5,11 @@ import '../data/home_repository.dart'; | @@ -5,13 +5,11 @@ import '../data/home_repository.dart'; | ||
5 | import '../domain/adapters/repository_adapter.dart'; | 5 | import '../domain/adapters/repository_adapter.dart'; |
6 | import '../presentation/controllers/home_controller.dart'; | 6 | import '../presentation/controllers/home_controller.dart'; |
7 | 7 | ||
8 | -class HomeBinding extends Binding { | 8 | +class HomeBinding extends Bindings { |
9 | @override | 9 | @override |
10 | - List<Bind> dependencies() { | ||
11 | - return [ | ||
12 | - Bind.lazyPut<IHomeProvider>(() => HomeProvider()), | ||
13 | - Bind.lazyPut<IHomeRepository>(() => HomeRepository(provider: Get.find())), | ||
14 | - Bind.lazyPut(() => HomeController(homeRepository: Get.find())), | ||
15 | - ]; | 10 | + void dependencies() { |
11 | + Get.lazyPut<IHomeProvider>(() => HomeProvider()); | ||
12 | + Get.lazyPut<IHomeRepository>(() => HomeRepository(provider: Get.find())); | ||
13 | + Get.lazyPut(() => HomeController(homeRepository: Get.find())); | ||
16 | } | 14 | } |
17 | } | 15 | } |
@@ -6,6 +6,7 @@ import 'package:get/get.dart'; | @@ -6,6 +6,7 @@ import 'package:get/get.dart'; | ||
6 | import '../controllers/home_controller.dart'; | 6 | import '../controllers/home_controller.dart'; |
7 | 7 | ||
8 | class CountryView extends GetView<HomeController> { | 8 | class CountryView extends GetView<HomeController> { |
9 | + const CountryView({Key? key}) : super(key: key); | ||
9 | @override | 10 | @override |
10 | Widget build(BuildContext context) { | 11 | Widget build(BuildContext context) { |
11 | return Container( | 12 | return Container( |
@@ -32,10 +33,11 @@ class CountryView extends GetView<HomeController> { | @@ -32,10 +33,11 @@ class CountryView extends GetView<HomeController> { | ||
32 | itemBuilder: (context, index) { | 33 | itemBuilder: (context, index) { |
33 | final country = controller.state.countries[index]; | 34 | final country = controller.state.countries[index]; |
34 | return ListTile( | 35 | return ListTile( |
35 | - onTap: () { | 36 | + onTap: () async { |
36 | //Get.rootDelegate.toNamed('/home/country'); | 37 | //Get.rootDelegate.toNamed('/home/country'); |
37 | - Get.rootDelegate | ||
38 | - .toNamed('/home/country/details?id=$index'); | 38 | + final data = await Get.toNamed( |
39 | + '/home/country/details?id=$index'); | ||
40 | + print(data); | ||
39 | }, | 41 | }, |
40 | trailing: CircleAvatar( | 42 | trailing: CircleAvatar( |
41 | backgroundImage: NetworkImage( | 43 | backgroundImage: NetworkImage( |
@@ -2,12 +2,14 @@ import 'dart:ui'; | @@ -2,12 +2,14 @@ import 'dart:ui'; | ||
2 | 2 | ||
3 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
4 | import 'package:get/get.dart'; | 4 | import 'package:get/get.dart'; |
5 | + | ||
5 | import '../controllers/home_controller.dart'; | 6 | import '../controllers/home_controller.dart'; |
6 | 7 | ||
7 | class DetailsView extends GetView<HomeController> { | 8 | class DetailsView extends GetView<HomeController> { |
9 | + const DetailsView({Key? key}) : super(key: key); | ||
8 | @override | 10 | @override |
9 | Widget build(BuildContext context) { | 11 | Widget build(BuildContext context) { |
10 | - final parameter = Get.rootDelegate.parameters; | 12 | + final parameter = context.params; //Get.parameters; |
11 | final country = controller.getCountryById(parameter['id'] ?? ''); | 13 | final country = controller.getCountryById(parameter['id'] ?? ''); |
12 | return Container( | 14 | return Container( |
13 | decoration: BoxDecoration( | 15 | decoration: BoxDecoration( |
@@ -76,6 +78,11 @@ class DetailsView extends GetView<HomeController> { | @@ -76,6 +78,11 @@ class DetailsView extends GetView<HomeController> { | ||
76 | '${country.totalRecovered}', | 78 | '${country.totalRecovered}', |
77 | style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold), | 79 | style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold), |
78 | ), | 80 | ), |
81 | + TextButton( | ||
82 | + onPressed: () { | ||
83 | + Get.back(result: 'djsoidjsoidj'); | ||
84 | + }, | ||
85 | + child: Text('back')) | ||
79 | ], | 86 | ], |
80 | )), | 87 | )), |
81 | ), | 88 | ), |
@@ -4,6 +4,8 @@ import 'package:get/get.dart'; | @@ -4,6 +4,8 @@ import 'package:get/get.dart'; | ||
4 | import '../controllers/home_controller.dart'; | 4 | import '../controllers/home_controller.dart'; |
5 | 5 | ||
6 | class HomeView extends GetView<HomeController> { | 6 | class HomeView extends GetView<HomeController> { |
7 | + const HomeView({Key? key}) : super(key: key); | ||
8 | + | ||
7 | @override | 9 | @override |
8 | Widget build(BuildContext context) { | 10 | Widget build(BuildContext context) { |
9 | return Container( | 11 | return Container( |
@@ -75,7 +77,8 @@ class HomeView extends GetView<HomeController> { | @@ -75,7 +77,8 @@ class HomeView extends GetView<HomeController> { | ||
75 | shape: StadiumBorder(), | 77 | shape: StadiumBorder(), |
76 | ), | 78 | ), |
77 | onPressed: () async { | 79 | onPressed: () async { |
78 | - await Get.rootDelegate.toNamed('/home/country'); | 80 | + //await Navigation Get.rootDelegate.toNamed('/home/country'); |
81 | + Get.toNamed('/home/country'); | ||
79 | }, | 82 | }, |
80 | child: Text( | 83 | child: Text( |
81 | 'fetch_country'.tr, | 84 | 'fetch_country'.tr, |
@@ -15,7 +15,7 @@ class AppPages { | @@ -15,7 +15,7 @@ class AppPages { | ||
15 | GetPage( | 15 | GetPage( |
16 | name: Routes.HOME, | 16 | name: Routes.HOME, |
17 | page: () => HomeView(), | 17 | page: () => HomeView(), |
18 | - binding: HomeBinding(), | 18 | + bindings: [HomeBinding()], |
19 | children: [ | 19 | children: [ |
20 | GetPage( | 20 | GetPage( |
21 | name: Routes.COUNTRY, | 21 | name: Routes.COUNTRY, |
@@ -27,6 +27,7 @@ class AppPages { | @@ -27,6 +27,7 @@ class AppPages { | ||
27 | ), | 27 | ), |
28 | ], | 28 | ], |
29 | ), | 29 | ), |
30 | - ]), | 30 | + ], |
31 | + ), | ||
31 | ]; | 32 | ]; |
32 | } | 33 | } |
@@ -4,4 +4,8 @@ abstract class Routes { | @@ -4,4 +4,8 @@ abstract class Routes { | ||
4 | static const HOME = '/home'; | 4 | static const HOME = '/home'; |
5 | static const COUNTRY = '/country'; | 5 | static const COUNTRY = '/country'; |
6 | static const DETAILS = '/details'; | 6 | static const DETAILS = '/details'; |
7 | + | ||
8 | + static const DASHBOARD = '/dashboard'; | ||
9 | + static const PROFILE = '/profile'; | ||
10 | + static const PRODUCTS = '/products'; | ||
7 | } | 11 | } |
@@ -5,29 +5,31 @@ import '../routes/app_pages.dart'; | @@ -5,29 +5,31 @@ import '../routes/app_pages.dart'; | ||
5 | 5 | ||
6 | class EnsureAuthMiddleware extends GetMiddleware { | 6 | class EnsureAuthMiddleware extends GetMiddleware { |
7 | @override | 7 | @override |
8 | - Future<GetNavConfig?> redirectDelegate(GetNavConfig route) async { | 8 | + Future<RouteDecoder?> redirect(RouteDecoder route) async { |
9 | // you can do whatever you want here | 9 | // you can do whatever you want here |
10 | // but it's preferable to make this method fast | 10 | // but it's preferable to make this method fast |
11 | // await Future.delayed(Duration(milliseconds: 500)); | 11 | // await Future.delayed(Duration(milliseconds: 500)); |
12 | 12 | ||
13 | if (!AuthService.to.isLoggedInValue) { | 13 | if (!AuthService.to.isLoggedInValue) { |
14 | - final newRoute = Routes.LOGIN_THEN(route.location!); | ||
15 | - return GetNavConfig.fromRoute(newRoute); | 14 | + final path = route.args.name as String; |
15 | + final newRoute = Routes.LOGIN_THEN(path); | ||
16 | + | ||
17 | + return RouteDecoder.fromRoute(newRoute); | ||
16 | } | 18 | } |
17 | - return await super.redirectDelegate(route); | 19 | + return await super.redirect(route); |
18 | } | 20 | } |
19 | } | 21 | } |
20 | 22 | ||
21 | class EnsureNotAuthedMiddleware extends GetMiddleware { | 23 | class EnsureNotAuthedMiddleware extends GetMiddleware { |
22 | @override | 24 | @override |
23 | - Future<GetNavConfig?> redirectDelegate(GetNavConfig route) async { | 25 | + Future<RouteDecoder?> redirect(RouteDecoder route) async { |
24 | if (AuthService.to.isLoggedInValue) { | 26 | if (AuthService.to.isLoggedInValue) { |
25 | //NEVER navigate to auth screen, when user is already authed | 27 | //NEVER navigate to auth screen, when user is already authed |
26 | return null; | 28 | return null; |
27 | 29 | ||
28 | //OR redirect user to another screen | 30 | //OR redirect user to another screen |
29 | - //return GetNavConfig.fromRoute(Routes.PROFILE); | 31 | + //return RouteDecoder.fromRoute(Routes.PROFILE); |
30 | } | 32 | } |
31 | - return await super.redirectDelegate(route); | 33 | + return await super.redirect(route); |
32 | } | 34 | } |
33 | } | 35 | } |
@@ -10,19 +10,19 @@ class HomeView extends GetView<HomeController> { | @@ -10,19 +10,19 @@ class HomeView extends GetView<HomeController> { | ||
10 | return GetRouterOutlet.builder( | 10 | return GetRouterOutlet.builder( |
11 | builder: (context, delegate, currentRoute) { | 11 | builder: (context, delegate, currentRoute) { |
12 | //This router outlet handles the appbar and the bottom navigation bar | 12 | //This router outlet handles the appbar and the bottom navigation bar |
13 | - final currentLocation = currentRoute?.location; | 13 | + final currentLocation = context.location; |
14 | var currentIndex = 0; | 14 | var currentIndex = 0; |
15 | - if (currentLocation?.startsWith(Routes.PRODUCTS) == true) { | 15 | + if (currentLocation.startsWith(Routes.PRODUCTS) == true) { |
16 | currentIndex = 2; | 16 | currentIndex = 2; |
17 | } | 17 | } |
18 | - if (currentLocation?.startsWith(Routes.PROFILE) == true) { | 18 | + if (currentLocation.startsWith(Routes.PROFILE) == true) { |
19 | currentIndex = 1; | 19 | currentIndex = 1; |
20 | } | 20 | } |
21 | return Scaffold( | 21 | return Scaffold( |
22 | body: GetRouterOutlet( | 22 | body: GetRouterOutlet( |
23 | initialRoute: Routes.DASHBOARD, | 23 | initialRoute: Routes.DASHBOARD, |
24 | // anchorRoute: Routes.HOME, | 24 | // anchorRoute: Routes.HOME, |
25 | - key: Get.nestedKey(Routes.HOME), | 25 | + // key: Get.nestedKey(Routes.HOME), |
26 | ), | 26 | ), |
27 | bottomNavigationBar: BottomNavigationBar( | 27 | bottomNavigationBar: BottomNavigationBar( |
28 | currentIndex: currentIndex, | 28 | currentIndex: currentIndex, |
@@ -31,9 +31,8 @@ class LoginView extends GetView<LoginController> { | @@ -31,9 +31,8 @@ class LoginView extends GetView<LoginController> { | ||
31 | ), | 31 | ), |
32 | onPressed: () { | 32 | onPressed: () { |
33 | AuthService.to.login(); | 33 | AuthService.to.login(); |
34 | - final thenTo = Get.rootDelegate.currentConfiguration! | ||
35 | - .currentPage!.parameters?['then']; | ||
36 | - Get.rootDelegate.offNamed(thenTo ?? Routes.HOME); | 34 | + final thenTo = context.params['then']; |
35 | + Get.offNamed(thenTo ?? Routes.HOME); | ||
37 | }, | 36 | }, |
38 | ), | 37 | ), |
39 | ], | 38 | ], |
@@ -31,8 +31,7 @@ class ProductsView extends GetView<ProductsController> { | @@ -31,8 +31,7 @@ class ProductsView extends GetView<ProductsController> { | ||
31 | final item = controller.products[index]; | 31 | final item = controller.products[index]; |
32 | return ListTile( | 32 | return ListTile( |
33 | onTap: () { | 33 | onTap: () { |
34 | - Get.rootDelegate | ||
35 | - .toNamed(Routes.PRODUCT_DETAILS(item.id)); | 34 | + Get.toNamed(Routes.PRODUCT_DETAILS(item.id)); |
36 | }, | 35 | }, |
37 | title: Text(item.name), | 36 | title: Text(item.name), |
38 | subtitle: Text(item.id), | 37 | subtitle: Text(item.id), |
@@ -39,7 +39,8 @@ class ProfileView extends GetView<ProfileController> { | @@ -39,7 +39,8 @@ class ProfileView extends GetView<ProfileController> { | ||
39 | Get.defaultDialog( | 39 | Get.defaultDialog( |
40 | title: 'Test Dialog In Home Outlet !!', | 40 | title: 'Test Dialog In Home Outlet !!', |
41 | barrierDismissible: true, | 41 | barrierDismissible: true, |
42 | - navigatorKey: Get.nestedKey(Routes.HOME), | 42 | + id: Routes.HOME, |
43 | + // navigatorKey: Get.nestedKey(Routes.HOME), | ||
43 | ); | 44 | ); |
44 | }, | 45 | }, |
45 | ) | 46 | ) |
@@ -21,7 +21,7 @@ class DrawerWidget extends StatelessWidget { | @@ -21,7 +21,7 @@ class DrawerWidget extends StatelessWidget { | ||
21 | ListTile( | 21 | ListTile( |
22 | title: Text('Home'), | 22 | title: Text('Home'), |
23 | onTap: () { | 23 | onTap: () { |
24 | - Get.rootDelegate.toNamed(Routes.HOME); | 24 | + Get.toNamed(Routes.HOME); |
25 | //to close the drawer | 25 | //to close the drawer |
26 | 26 | ||
27 | Navigator.of(context).pop(); | 27 | Navigator.of(context).pop(); |
@@ -30,7 +30,7 @@ class DrawerWidget extends StatelessWidget { | @@ -30,7 +30,7 @@ class DrawerWidget extends StatelessWidget { | ||
30 | ListTile( | 30 | ListTile( |
31 | title: Text('Settings'), | 31 | title: Text('Settings'), |
32 | onTap: () { | 32 | onTap: () { |
33 | - Get.rootDelegate.toNamed(Routes.SETTINGS); | 33 | + Get.toNamed(Routes.SETTINGS); |
34 | //to close the drawer | 34 | //to close the drawer |
35 | 35 | ||
36 | Navigator.of(context).pop(); | 36 | Navigator.of(context).pop(); |
@@ -46,7 +46,7 @@ class DrawerWidget extends StatelessWidget { | @@ -46,7 +46,7 @@ class DrawerWidget extends StatelessWidget { | ||
46 | ), | 46 | ), |
47 | onTap: () { | 47 | onTap: () { |
48 | AuthService.to.logout(); | 48 | AuthService.to.logout(); |
49 | - Get.rootDelegate.toNamed(Routes.LOGIN); | 49 | + Get.toNamed(Routes.LOGIN); |
50 | //to close the drawer | 50 | //to close the drawer |
51 | 51 | ||
52 | Navigator.of(context).pop(); | 52 | Navigator.of(context).pop(); |
@@ -61,7 +61,7 @@ class DrawerWidget extends StatelessWidget { | @@ -61,7 +61,7 @@ class DrawerWidget extends StatelessWidget { | ||
61 | ), | 61 | ), |
62 | ), | 62 | ), |
63 | onTap: () { | 63 | onTap: () { |
64 | - Get.rootDelegate.toNamed(Routes.LOGIN); | 64 | + Get.toNamed(Routes.LOGIN); |
65 | //to close the drawer | 65 | //to close the drawer |
66 | 66 | ||
67 | Navigator.of(context).pop(); | 67 | Navigator.of(context).pop(); |
@@ -10,11 +10,11 @@ class RootView extends GetView<RootController> { | @@ -10,11 +10,11 @@ class RootView extends GetView<RootController> { | ||
10 | Widget build(BuildContext context) { | 10 | Widget build(BuildContext context) { |
11 | return GetRouterOutlet.builder( | 11 | return GetRouterOutlet.builder( |
12 | builder: (context, delegate, current) { | 12 | builder: (context, delegate, current) { |
13 | - final title = current?.location; | 13 | + final title = context.location; |
14 | return Scaffold( | 14 | return Scaffold( |
15 | drawer: DrawerWidget(), | 15 | drawer: DrawerWidget(), |
16 | appBar: AppBar( | 16 | appBar: AppBar( |
17 | - title: Text(title ?? ''), | 17 | + title: Text(title), |
18 | centerTitle: true, | 18 | centerTitle: true, |
19 | ), | 19 | ), |
20 | body: GetRouterOutlet( | 20 | body: GetRouterOutlet( |
@@ -29,7 +29,7 @@ class AppPages { | @@ -29,7 +29,7 @@ class AppPages { | ||
29 | GetPage( | 29 | GetPage( |
30 | name: '/', | 30 | name: '/', |
31 | page: () => RootView(), | 31 | page: () => RootView(), |
32 | - binding: RootBinding(), | 32 | + bindings: [RootBinding()], |
33 | participatesInRootNavigator: true, | 33 | participatesInRootNavigator: true, |
34 | preventDuplicates: true, | 34 | preventDuplicates: true, |
35 | children: [ | 35 | children: [ |
@@ -40,19 +40,23 @@ class AppPages { | @@ -40,19 +40,23 @@ class AppPages { | ||
40 | ], | 40 | ], |
41 | name: _Paths.LOGIN, | 41 | name: _Paths.LOGIN, |
42 | page: () => LoginView(), | 42 | page: () => LoginView(), |
43 | - binding: LoginBinding(), | 43 | + bindings: [LoginBinding()], |
44 | ), | 44 | ), |
45 | GetPage( | 45 | GetPage( |
46 | preventDuplicates: true, | 46 | preventDuplicates: true, |
47 | name: _Paths.HOME, | 47 | name: _Paths.HOME, |
48 | page: () => HomeView(), | 48 | page: () => HomeView(), |
49 | - binding: HomeBinding(), | 49 | + bindings: [ |
50 | + HomeBinding(), | ||
51 | + ], | ||
50 | title: null, | 52 | title: null, |
51 | children: [ | 53 | children: [ |
52 | GetPage( | 54 | GetPage( |
53 | name: _Paths.DASHBOARD, | 55 | name: _Paths.DASHBOARD, |
54 | page: () => DashboardView(), | 56 | page: () => DashboardView(), |
55 | - binding: DashboardBinding(), | 57 | + bindings: [ |
58 | + DashboardBinding(), | ||
59 | + ], | ||
56 | ), | 60 | ), |
57 | GetPage( | 61 | GetPage( |
58 | middlewares: [ | 62 | middlewares: [ |
@@ -63,19 +67,19 @@ class AppPages { | @@ -63,19 +67,19 @@ class AppPages { | ||
63 | page: () => ProfileView(), | 67 | page: () => ProfileView(), |
64 | title: 'Profile', | 68 | title: 'Profile', |
65 | transition: Transition.size, | 69 | transition: Transition.size, |
66 | - binding: ProfileBinding(), | 70 | + bindings: [ProfileBinding()], |
67 | ), | 71 | ), |
68 | GetPage( | 72 | GetPage( |
69 | name: _Paths.PRODUCTS, | 73 | name: _Paths.PRODUCTS, |
70 | page: () => ProductsView(), | 74 | page: () => ProductsView(), |
71 | title: 'Products', | 75 | title: 'Products', |
72 | transition: Transition.zoom, | 76 | transition: Transition.zoom, |
73 | - binding: ProductsBinding(), | 77 | + bindings: [ProductsBinding()], |
74 | children: [ | 78 | children: [ |
75 | GetPage( | 79 | GetPage( |
76 | name: _Paths.PRODUCT_DETAILS, | 80 | name: _Paths.PRODUCT_DETAILS, |
77 | page: () => ProductDetailsView(), | 81 | page: () => ProductDetailsView(), |
78 | - binding: ProductDetailsBinding(), | 82 | + bindings: [ProductDetailsBinding()], |
79 | middlewares: [ | 83 | middlewares: [ |
80 | //only enter this route when authed | 84 | //only enter this route when authed |
81 | EnsureAuthMiddleware(), | 85 | EnsureAuthMiddleware(), |
@@ -88,7 +92,9 @@ class AppPages { | @@ -88,7 +92,9 @@ class AppPages { | ||
88 | GetPage( | 92 | GetPage( |
89 | name: _Paths.SETTINGS, | 93 | name: _Paths.SETTINGS, |
90 | page: () => SettingsView(), | 94 | page: () => SettingsView(), |
91 | - binding: SettingsBinding(), | 95 | + bindings: [ |
96 | + SettingsBinding(), | ||
97 | + ], | ||
92 | ), | 98 | ), |
93 | ], | 99 | ], |
94 | ), | 100 | ), |
@@ -7,7 +7,7 @@ export 'get_common/get_reset.dart'; | @@ -7,7 +7,7 @@ export 'get_common/get_reset.dart'; | ||
7 | export 'get_connect/connect.dart'; | 7 | export 'get_connect/connect.dart'; |
8 | export 'get_core/get_core.dart'; | 8 | export 'get_core/get_core.dart'; |
9 | export 'get_instance/get_instance.dart'; | 9 | export 'get_instance/get_instance.dart'; |
10 | -export 'get_navigation/get_navigation.dart'; | 10 | +export 'get_navigation/get_navigation.dart' hide FirstWhereOrNullExt; |
11 | export 'get_rx/get_rx.dart'; | 11 | export 'get_rx/get_rx.dart'; |
12 | export 'get_state_manager/get_state_manager.dart'; | 12 | export 'get_state_manager/get_state_manager.dart'; |
13 | export 'get_utils/get_utils.dart'; | 13 | export 'get_utils/get_utils.dart'; |
@@ -2,11 +2,6 @@ library get_navigation; | @@ -2,11 +2,6 @@ library get_navigation; | ||
2 | 2 | ||
3 | export 'src/bottomsheet/bottomsheet.dart'; | 3 | export 'src/bottomsheet/bottomsheet.dart'; |
4 | export 'src/extension_navigation.dart'; | 4 | export 'src/extension_navigation.dart'; |
5 | -export 'src/nav2/get_information_parser.dart'; | ||
6 | -export 'src/nav2/get_nav_config.dart'; | ||
7 | -export 'src/nav2/get_navigator.dart'; | ||
8 | -export 'src/nav2/get_router_delegate.dart'; | ||
9 | -export 'src/nav2/router_outlet.dart'; | ||
10 | export 'src/root/get_cupertino_app.dart'; | 5 | export 'src/root/get_cupertino_app.dart'; |
11 | export 'src/root/get_material_app.dart'; | 6 | export 'src/root/get_material_app.dart'; |
12 | export 'src/root/internacionalization.dart'; | 7 | export 'src/root/internacionalization.dart'; |
@@ -14,6 +9,7 @@ export 'src/root/root_controller.dart'; | @@ -14,6 +9,7 @@ export 'src/root/root_controller.dart'; | ||
14 | export 'src/routes/custom_transition.dart'; | 9 | export 'src/routes/custom_transition.dart'; |
15 | export 'src/routes/default_route.dart'; | 10 | export 'src/routes/default_route.dart'; |
16 | export 'src/routes/get_route.dart'; | 11 | export 'src/routes/get_route.dart'; |
12 | +export 'src/routes/index.dart'; | ||
17 | export 'src/routes/observers/route_observer.dart'; | 13 | export 'src/routes/observers/route_observer.dart'; |
18 | export 'src/routes/route_middleware.dart'; | 14 | export 'src/routes/route_middleware.dart'; |
19 | export 'src/routes/transitions_type.dart'; | 15 | export 'src/routes/transitions_type.dart'; |
@@ -5,16 +5,14 @@ import 'package:flutter/scheduler.dart'; | @@ -5,16 +5,14 @@ import 'package:flutter/scheduler.dart'; | ||
5 | 5 | ||
6 | import '../../get_core/get_core.dart'; | 6 | import '../../get_core/get_core.dart'; |
7 | import '../../get_instance/src/bindings_interface.dart'; | 7 | import '../../get_instance/src/bindings_interface.dart'; |
8 | -import '../../get_state_manager/src/simple/get_state.dart'; | ||
9 | import '../../get_utils/get_utils.dart'; | 8 | import '../../get_utils/get_utils.dart'; |
10 | import '../get_navigation.dart'; | 9 | import '../get_navigation.dart'; |
11 | import 'dialog/dialog_route.dart'; | 10 | import 'dialog/dialog_route.dart'; |
12 | -import 'root/parse_route.dart'; | ||
13 | 11 | ||
14 | /// It replaces the Flutter Navigator, but needs no context. | 12 | /// It replaces the Flutter Navigator, but needs no context. |
15 | /// You can to use navigator.push(YourRoute()) rather | 13 | /// You can to use navigator.push(YourRoute()) rather |
16 | /// Navigator.push(context, YourRoute()); | 14 | /// Navigator.push(context, YourRoute()); |
17 | -NavigatorState? get navigator => GetNavigation(Get).key.currentState; | 15 | +NavigatorState? get navigator => GetNavigationExt(Get).key.currentState; |
18 | 16 | ||
19 | extension ExtensionBottomSheet on GetInterface { | 17 | extension ExtensionBottomSheet on GetInterface { |
20 | Future<T?> bottomSheet<T>( | 18 | Future<T?> bottomSheet<T>( |
@@ -78,6 +76,7 @@ extension ExtensionDialog on GetInterface { | @@ -78,6 +76,7 @@ extension ExtensionDialog on GetInterface { | ||
78 | Curve? transitionCurve, | 76 | Curve? transitionCurve, |
79 | String? name, | 77 | String? name, |
80 | RouteSettings? routeSettings, | 78 | RouteSettings? routeSettings, |
79 | + dynamic id, | ||
81 | }) { | 80 | }) { |
82 | assert(debugCheckHasMaterialLocalizations(context!)); | 81 | assert(debugCheckHasMaterialLocalizations(context!)); |
83 | 82 | ||
@@ -110,12 +109,13 @@ extension ExtensionDialog on GetInterface { | @@ -110,12 +109,13 @@ extension ExtensionDialog on GetInterface { | ||
110 | navigatorKey: navigatorKey, | 109 | navigatorKey: navigatorKey, |
111 | routeSettings: | 110 | routeSettings: |
112 | routeSettings ?? RouteSettings(arguments: arguments, name: name), | 111 | routeSettings ?? RouteSettings(arguments: arguments, name: name), |
112 | + id: id, | ||
113 | ); | 113 | ); |
114 | } | 114 | } |
115 | 115 | ||
116 | /// Api from showGeneralDialog with no context | 116 | /// Api from showGeneralDialog with no context |
117 | - Future<T?> generalDialog<T>({ | ||
118 | - required RoutePageBuilder pageBuilder, | 117 | + Future<T?> generalDialog<T>( |
118 | + {required RoutePageBuilder pageBuilder, | ||
119 | bool barrierDismissible = false, | 119 | bool barrierDismissible = false, |
120 | String? barrierLabel, | 120 | String? barrierLabel, |
121 | Color barrierColor = const Color(0x80000000), | 121 | Color barrierColor = const Color(0x80000000), |
@@ -123,9 +123,10 @@ extension ExtensionDialog on GetInterface { | @@ -123,9 +123,10 @@ extension ExtensionDialog on GetInterface { | ||
123 | RouteTransitionsBuilder? transitionBuilder, | 123 | RouteTransitionsBuilder? transitionBuilder, |
124 | GlobalKey<NavigatorState>? navigatorKey, | 124 | GlobalKey<NavigatorState>? navigatorKey, |
125 | RouteSettings? routeSettings, | 125 | RouteSettings? routeSettings, |
126 | - }) { | 126 | + dynamic id}) { |
127 | assert(!barrierDismissible || barrierLabel != null); | 127 | assert(!barrierDismissible || barrierLabel != null); |
128 | - final nav = navigatorKey?.currentState ?? | 128 | + final key = navigatorKey ?? Get.nestedKey(id)?.navigatorKey; |
129 | + final nav = key?.currentState ?? | ||
129 | Navigator.of(overlayContext!, | 130 | Navigator.of(overlayContext!, |
130 | rootNavigator: | 131 | rootNavigator: |
131 | true); //overlay context will always return the root navigator | 132 | true); //overlay context will always return the root navigator |
@@ -148,6 +149,7 @@ extension ExtensionDialog on GetInterface { | @@ -148,6 +149,7 @@ extension ExtensionDialog on GetInterface { | ||
148 | EdgeInsetsGeometry? titlePadding, | 149 | EdgeInsetsGeometry? titlePadding, |
149 | TextStyle? titleStyle, | 150 | TextStyle? titleStyle, |
150 | Widget? content, | 151 | Widget? content, |
152 | + dynamic id, | ||
151 | EdgeInsetsGeometry? contentPadding, | 153 | EdgeInsetsGeometry? contentPadding, |
152 | VoidCallback? onConfirm, | 154 | VoidCallback? onConfirm, |
153 | VoidCallback? onCancel, | 155 | VoidCallback? onCancel, |
@@ -269,6 +271,7 @@ extension ExtensionDialog on GetInterface { | @@ -269,6 +271,7 @@ extension ExtensionDialog on GetInterface { | ||
269 | : baseAlertDialog, | 271 | : baseAlertDialog, |
270 | barrierDismissible: barrierDismissible, | 272 | barrierDismissible: barrierDismissible, |
271 | navigatorKey: navigatorKey, | 273 | navigatorKey: navigatorKey, |
274 | + id: id, | ||
272 | ); | 275 | ); |
273 | } | 276 | } |
274 | } | 277 | } |
@@ -474,7 +477,7 @@ extension ExtensionSnackbar on GetInterface { | @@ -474,7 +477,7 @@ extension ExtensionSnackbar on GetInterface { | ||
474 | } | 477 | } |
475 | } | 478 | } |
476 | 479 | ||
477 | -extension GetNavigation on GetInterface { | 480 | +extension GetNavigationExt on GetInterface { |
478 | /// **Navigation.push()** shortcut.<br><br> | 481 | /// **Navigation.push()** shortcut.<br><br> |
479 | /// | 482 | /// |
480 | /// Pushes a new `page` to the stack | 483 | /// Pushes a new `page` to the stack |
@@ -499,9 +502,8 @@ extension GetNavigation on GetInterface { | @@ -499,9 +502,8 @@ extension GetNavigation on GetInterface { | ||
499 | /// | 502 | /// |
500 | /// By default, GetX will prevent you from push a route that you already in, | 503 | /// By default, GetX will prevent you from push a route that you already in, |
501 | /// if you want to push anyway, set [preventDuplicates] to false | 504 | /// if you want to push anyway, set [preventDuplicates] to false |
502 | - Future<T?>? to<T>( | ||
503 | - dynamic page, { | ||
504 | - bool? opaque, | 505 | + Future<T?>? to<T>(Widget Function() page, |
506 | + {bool? opaque, | ||
505 | Transition? transition, | 507 | Transition? transition, |
506 | Curve? curve, | 508 | Curve? curve, |
507 | Duration? duration, | 509 | Duration? duration, |
@@ -509,56 +511,51 @@ extension GetNavigation on GetInterface { | @@ -509,56 +511,51 @@ extension GetNavigation on GetInterface { | ||
509 | String? routeName, | 511 | String? routeName, |
510 | bool fullscreenDialog = false, | 512 | bool fullscreenDialog = false, |
511 | dynamic arguments, | 513 | dynamic arguments, |
512 | - Binding? binding, | 514 | + List<BindingsInterface>? bindings, |
513 | bool preventDuplicates = true, | 515 | bool preventDuplicates = true, |
514 | bool? popGesture, | 516 | bool? popGesture, |
515 | bool showCupertinoParallax = true, | 517 | bool showCupertinoParallax = true, |
516 | double Function(BuildContext context)? gestureWidth, | 518 | double Function(BuildContext context)? gestureWidth, |
517 | - }) { | ||
518 | - // var routeName = "/${page.runtimeType}"; | ||
519 | - routeName ??= "/${page.runtimeType}"; | ||
520 | - routeName = _cleanRouteName(routeName); | ||
521 | - if (preventDuplicates && routeName == currentRoute) { | ||
522 | - return null; | ||
523 | - } | ||
524 | - return global(id).currentState?.push<T>( | ||
525 | - GetPageRoute<T>( | ||
526 | - opaque: opaque ?? true, | ||
527 | - page: _resolvePage(page, 'to'), | 519 | + bool rebuildStack = true, |
520 | + PreventDuplicateHandlingMode preventDuplicateHandlingMode = | ||
521 | + PreventDuplicateHandlingMode.ReorderRoutes}) { | ||
522 | + searchDelegate(id).to( | ||
523 | + page, | ||
524 | + opaque: opaque, | ||
525 | + transition: transition, | ||
526 | + curve: curve, | ||
527 | + duration: duration, | ||
528 | + id: id, | ||
528 | routeName: routeName, | 529 | routeName: routeName, |
529 | - gestureWidth: gestureWidth, | ||
530 | - showCupertinoParallax: showCupertinoParallax, | ||
531 | - settings: RouteSettings( | ||
532 | - name: routeName, | ||
533 | - arguments: arguments, | ||
534 | - ), | ||
535 | - popGesture: popGesture ?? defaultPopGesture, | ||
536 | - transition: transition ?? defaultTransition, | ||
537 | - curve: curve ?? defaultTransitionCurve, | ||
538 | fullscreenDialog: fullscreenDialog, | 530 | fullscreenDialog: fullscreenDialog, |
539 | - binding: binding, | ||
540 | - transitionDuration: duration ?? defaultTransitionDuration, | ||
541 | - ), | 531 | + arguments: arguments, |
532 | + bindings: bindings, | ||
533 | + preventDuplicates: preventDuplicates, | ||
534 | + popGesture: popGesture, | ||
535 | + showCupertinoParallax: showCupertinoParallax, | ||
536 | + gestureWidth: gestureWidth, | ||
537 | + rebuildStack: rebuildStack, | ||
538 | + preventDuplicateHandlingMode: preventDuplicateHandlingMode, | ||
542 | ); | 539 | ); |
543 | } | 540 | } |
544 | 541 | ||
545 | - GetPageBuilder _resolvePage(dynamic page, String method) { | ||
546 | - if (page is GetPageBuilder) { | ||
547 | - return page; | ||
548 | - } else if (page is Widget) { | ||
549 | - Get.log( | ||
550 | - '''WARNING, consider using: "Get.$method(() => Page())" instead of "Get.$method(Page())". | ||
551 | -Using a widget function instead of a widget fully guarantees that the widget and its controllers will be removed from memory when they are no longer used. | ||
552 | - '''); | ||
553 | - return () => page; | ||
554 | - } else if (page is String) { | ||
555 | - throw '''Unexpected String, | ||
556 | -use toNamed() instead'''; | ||
557 | - } else { | ||
558 | - throw '''Unexpected format, | ||
559 | -you can only use widgets and widget functions here'''; | ||
560 | - } | ||
561 | - } | 542 | +// GetPageBuilder _resolvePage(dynamic page, String method) { |
543 | +// if (page is GetPageBuilder) { | ||
544 | +// return page; | ||
545 | +// } else if (page is Widget) { | ||
546 | +// Get.log( | ||
547 | +// '''WARNING, consider using: "Get.$method(() => Page())" instead of "Get.$method(Page())". | ||
548 | +// Using a widget function instead of a widget fully guarantees that the widget and its controllers will be removed from memory when they are no longer used. | ||
549 | +// '''); | ||
550 | +// return () => page; | ||
551 | +// } else if (page is String) { | ||
552 | +// throw '''Unexpected String, | ||
553 | +// use toNamed() instead'''; | ||
554 | +// } else { | ||
555 | +// throw '''Unexpected format, | ||
556 | +// you can only use widgets and widget functions here'''; | ||
557 | +// } | ||
558 | +// } | ||
562 | 559 | ||
563 | /// **Navigation.pushNamed()** shortcut.<br><br> | 560 | /// **Navigation.pushNamed()** shortcut.<br><br> |
564 | /// | 561 | /// |
@@ -592,9 +589,12 @@ you can only use widgets and widget functions here'''; | @@ -592,9 +589,12 @@ you can only use widgets and widget functions here'''; | ||
592 | page = uri.toString(); | 589 | page = uri.toString(); |
593 | } | 590 | } |
594 | 591 | ||
595 | - return global(id).currentState?.pushNamed<T>( | 592 | + return searchDelegate(id).toNamed( |
596 | page, | 593 | page, |
597 | arguments: arguments, | 594 | arguments: arguments, |
595 | + id: id, | ||
596 | + preventDuplicates: preventDuplicates, | ||
597 | + parameters: parameters, | ||
598 | ); | 598 | ); |
599 | } | 599 | } |
600 | 600 | ||
@@ -618,20 +618,22 @@ you can only use widgets and widget functions here'''; | @@ -618,20 +618,22 @@ you can only use widgets and widget functions here'''; | ||
618 | String page, { | 618 | String page, { |
619 | dynamic arguments, | 619 | dynamic arguments, |
620 | int? id, | 620 | int? id, |
621 | - bool preventDuplicates = true, | ||
622 | Map<String, String>? parameters, | 621 | Map<String, String>? parameters, |
623 | }) { | 622 | }) { |
624 | - if (preventDuplicates && page == currentRoute) { | ||
625 | - return null; | ||
626 | - } | 623 | + // if (preventDuplicates && page == currentRoute) { |
624 | + // return null; | ||
625 | + // } | ||
627 | 626 | ||
628 | if (parameters != null) { | 627 | if (parameters != null) { |
629 | final uri = Uri(path: page, queryParameters: parameters); | 628 | final uri = Uri(path: page, queryParameters: parameters); |
630 | page = uri.toString(); | 629 | page = uri.toString(); |
631 | } | 630 | } |
632 | - return global(id).currentState?.pushReplacementNamed( | 631 | + return searchDelegate(id).offNamed( |
633 | page, | 632 | page, |
634 | arguments: arguments, | 633 | arguments: arguments, |
634 | + id: id, | ||
635 | + // preventDuplicates: preventDuplicates, | ||
636 | + parameters: parameters, | ||
635 | ); | 637 | ); |
636 | } | 638 | } |
637 | 639 | ||
@@ -648,34 +650,10 @@ you can only use widgets and widget functions here'''; | @@ -648,34 +650,10 @@ you can only use widgets and widget functions here'''; | ||
648 | /// or also like this: | 650 | /// or also like this: |
649 | /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the | 651 | /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the |
650 | /// dialog is closed | 652 | /// dialog is closed |
651 | - void until(RoutePredicate predicate, {int? id}) { | ||
652 | - // if (key.currentState.mounted) // add this if appear problems on future with route navigate | ||
653 | - // when widget don't mounted | ||
654 | - return global(id).currentState?.popUntil(predicate); | ||
655 | - } | ||
656 | - | ||
657 | - /// **Navigation.pushAndRemoveUntil()** shortcut.<br><br> | ||
658 | - /// | ||
659 | - /// Push the given `page`, and then pop several pages in the stack until | ||
660 | - /// [predicate] returns true | ||
661 | - /// | ||
662 | - /// [id] is for when you are using nested navigation, | ||
663 | - /// as explained in documentation | ||
664 | - /// | ||
665 | - /// Obs: unlike other get methods, this one you need to send a function | ||
666 | - /// that returns the widget to the page argument, like this: | ||
667 | - /// Get.offUntil(GetPageRoute(page: () => HomePage()), predicate) | ||
668 | - /// | ||
669 | - /// [predicate] can be used like this: | ||
670 | - /// `Get.offUntil(page, (route) => (route as GetPageRoute).routeName == '/home')` | ||
671 | - /// to pop routes in stack until home, | ||
672 | - /// or also like this: | ||
673 | - /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the dialog | ||
674 | - /// is closed | ||
675 | - Future<T?>? offUntil<T>(Route<T> page, RoutePredicate predicate, {int? id}) { | 653 | + void until(bool Function(GetPage<dynamic>) predicate, {int? id}) { |
676 | // if (key.currentState.mounted) // add this if appear problems on future with route navigate | 654 | // if (key.currentState.mounted) // add this if appear problems on future with route navigate |
677 | // when widget don't mounted | 655 | // when widget don't mounted |
678 | - return global(id).currentState?.pushAndRemoveUntil<T>(page, predicate); | 656 | + return searchDelegate(id).backUntil(predicate); |
679 | } | 657 | } |
680 | 658 | ||
681 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> | 659 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> |
@@ -698,7 +676,7 @@ you can only use widgets and widget functions here'''; | @@ -698,7 +676,7 @@ you can only use widgets and widget functions here'''; | ||
698 | /// Note: Always put a slash on the route name ('/page1'), to avoid unexpected errors | 676 | /// Note: Always put a slash on the route name ('/page1'), to avoid unexpected errors |
699 | Future<T?>? offNamedUntil<T>( | 677 | Future<T?>? offNamedUntil<T>( |
700 | String page, | 678 | String page, |
701 | - RoutePredicate predicate, { | 679 | + bool Function(GetPage<dynamic>)? predicate, { |
702 | int? id, | 680 | int? id, |
703 | dynamic arguments, | 681 | dynamic arguments, |
704 | Map<String, String>? parameters, | 682 | Map<String, String>? parameters, |
@@ -708,10 +686,12 @@ you can only use widgets and widget functions here'''; | @@ -708,10 +686,12 @@ you can only use widgets and widget functions here'''; | ||
708 | page = uri.toString(); | 686 | page = uri.toString(); |
709 | } | 687 | } |
710 | 688 | ||
711 | - return global(id).currentState?.pushNamedAndRemoveUntil<T>( | 689 | + return searchDelegate(id).offNamedUntil<T>( |
712 | page, | 690 | page, |
713 | - predicate, | 691 | + predicate: predicate, |
692 | + id: id, | ||
714 | arguments: arguments, | 693 | arguments: arguments, |
694 | + parameters: parameters, | ||
715 | ); | 695 | ); |
716 | } | 696 | } |
717 | 697 | ||
@@ -737,7 +717,7 @@ you can only use widgets and widget functions here'''; | @@ -737,7 +717,7 @@ you can only use widgets and widget functions here'''; | ||
737 | final uri = Uri(path: page, queryParameters: parameters); | 717 | final uri = Uri(path: page, queryParameters: parameters); |
738 | page = uri.toString(); | 718 | page = uri.toString(); |
739 | } | 719 | } |
740 | - return global(id).currentState?.popAndPushNamed( | 720 | + return searchDelegate(id).backAndtoNamed( |
741 | page, | 721 | page, |
742 | arguments: arguments, | 722 | arguments: arguments, |
743 | result: result, | 723 | result: result, |
@@ -750,8 +730,8 @@ you can only use widgets and widget functions here'''; | @@ -750,8 +730,8 @@ you can only use widgets and widget functions here'''; | ||
750 | /// | 730 | /// |
751 | /// [id] is for when you are using nested navigation, | 731 | /// [id] is for when you are using nested navigation, |
752 | /// as explained in documentation | 732 | /// as explained in documentation |
753 | - void removeRoute(Route<dynamic> route, {int? id}) { | ||
754 | - return global(id).currentState?.removeRoute(route); | 733 | + void removeRoute(String name, {int? id}) { |
734 | + return searchDelegate(id).removeRoute(name); | ||
755 | } | 735 | } |
756 | 736 | ||
757 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> | 737 | /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> |
@@ -776,7 +756,7 @@ you can only use widgets and widget functions here'''; | @@ -776,7 +756,7 @@ you can only use widgets and widget functions here'''; | ||
776 | /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors | 756 | /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors |
777 | Future<T?>? offAllNamed<T>( | 757 | Future<T?>? offAllNamed<T>( |
778 | String newRouteName, { | 758 | String newRouteName, { |
779 | - RoutePredicate? predicate, | 759 | + // bool Function(GetPage<dynamic>)? predicate, |
780 | dynamic arguments, | 760 | dynamic arguments, |
781 | int? id, | 761 | int? id, |
782 | Map<String, String>? parameters, | 762 | Map<String, String>? parameters, |
@@ -786,10 +766,12 @@ you can only use widgets and widget functions here'''; | @@ -786,10 +766,12 @@ you can only use widgets and widget functions here'''; | ||
786 | newRouteName = uri.toString(); | 766 | newRouteName = uri.toString(); |
787 | } | 767 | } |
788 | 768 | ||
789 | - return global(id).currentState?.pushNamedAndRemoveUntil<T>( | 769 | + return searchDelegate(id).offAllNamed<T>( |
790 | newRouteName, | 770 | newRouteName, |
791 | - predicate ?? (_) => false, | 771 | + //predicate: predicate ?? (_) => false, |
792 | arguments: arguments, | 772 | arguments: arguments, |
773 | + id: id, | ||
774 | + parameters: parameters, | ||
793 | ); | 775 | ); |
794 | } | 776 | } |
795 | 777 | ||
@@ -819,6 +801,13 @@ you can only use widgets and widget functions here'''; | @@ -819,6 +801,13 @@ you can only use widgets and widget functions here'''; | ||
819 | bool canPop = true, | 801 | bool canPop = true, |
820 | int? id, | 802 | int? id, |
821 | }) { | 803 | }) { |
804 | + //TODO: remove this when change own api to Dialog and BottomSheets | ||
805 | + //to declarative way | ||
806 | + if (isDialogOpen! || isBottomSheetOpen!) { | ||
807 | + searchDelegate(id).navigatorKey.currentState?.pop(); | ||
808 | + return; | ||
809 | + } | ||
810 | + | ||
822 | //TODO: This code brings compatibility of the new snackbar with GetX 4, | 811 | //TODO: This code brings compatibility of the new snackbar with GetX 4, |
823 | // remove this code in version 5 | 812 | // remove this code in version 5 |
824 | if (isSnackbarOpen && !closeOverlays) { | 813 | if (isSnackbarOpen && !closeOverlays) { |
@@ -832,16 +821,21 @@ you can only use widgets and widget functions here'''; | @@ -832,16 +821,21 @@ you can only use widgets and widget functions here'''; | ||
832 | if (isSnackbarOpen) { | 821 | if (isSnackbarOpen) { |
833 | closeAllSnackbars(); | 822 | closeAllSnackbars(); |
834 | } | 823 | } |
835 | - navigator?.popUntil((route) { | ||
836 | - return (!isDialogOpen! && !isBottomSheetOpen!); | ||
837 | - }); | 824 | + |
825 | + while ((isDialogOpen! && isBottomSheetOpen!)) { | ||
826 | + searchDelegate(id).navigatorKey.currentState?.pop(); | ||
827 | + } | ||
828 | + | ||
829 | + // navigator?.popUntil((route) { | ||
830 | + // return; | ||
831 | + // }); | ||
838 | } | 832 | } |
839 | if (canPop) { | 833 | if (canPop) { |
840 | - if (global(id).currentState?.canPop() == true) { | ||
841 | - global(id).currentState?.pop<T>(result); | 834 | + if (searchDelegate(id).canBack == true) { |
835 | + searchDelegate(id).back<T>(result); | ||
842 | } | 836 | } |
843 | } else { | 837 | } else { |
844 | - global(id).currentState?.pop<T>(result); | 838 | + searchDelegate(id).back<T>(result); |
845 | } | 839 | } |
846 | } | 840 | } |
847 | 841 | ||
@@ -856,7 +850,7 @@ you can only use widgets and widget functions here'''; | @@ -856,7 +850,7 @@ you can only use widgets and widget functions here'''; | ||
856 | times = 1; | 850 | times = 1; |
857 | } | 851 | } |
858 | var count = 0; | 852 | var count = 0; |
859 | - var back = global(id).currentState?.popUntil((route) => count++ == times); | 853 | + var back = searchDelegate(id).backUntil((route) => count++ == times); |
860 | 854 | ||
861 | return back; | 855 | return back; |
862 | } | 856 | } |
@@ -887,15 +881,15 @@ you can only use widgets and widget functions here'''; | @@ -887,15 +881,15 @@ you can only use widgets and widget functions here'''; | ||
887 | /// By default, GetX will prevent you from push a route that you already in, | 881 | /// By default, GetX will prevent you from push a route that you already in, |
888 | /// if you want to push anyway, set [preventDuplicates] to false | 882 | /// if you want to push anyway, set [preventDuplicates] to false |
889 | Future<T?>? off<T>( | 883 | Future<T?>? off<T>( |
890 | - dynamic page, { | ||
891 | - bool opaque = false, | 884 | + Widget Function() page, { |
885 | + bool? opaque, | ||
892 | Transition? transition, | 886 | Transition? transition, |
893 | Curve? curve, | 887 | Curve? curve, |
894 | bool? popGesture, | 888 | bool? popGesture, |
895 | int? id, | 889 | int? id, |
896 | String? routeName, | 890 | String? routeName, |
897 | dynamic arguments, | 891 | dynamic arguments, |
898 | - Binding? binding, | 892 | + List<BindingsInterface>? bindings, |
899 | bool fullscreenDialog = false, | 893 | bool fullscreenDialog = false, |
900 | bool preventDuplicates = true, | 894 | bool preventDuplicates = true, |
901 | Duration? duration, | 895 | Duration? duration, |
@@ -906,21 +900,34 @@ you can only use widgets and widget functions here'''; | @@ -906,21 +900,34 @@ you can only use widgets and widget functions here'''; | ||
906 | if (preventDuplicates && routeName == currentRoute) { | 900 | if (preventDuplicates && routeName == currentRoute) { |
907 | return null; | 901 | return null; |
908 | } | 902 | } |
909 | - return global(id).currentState?.pushReplacement(GetPageRoute( | ||
910 | - opaque: opaque, | ||
911 | - gestureWidth: gestureWidth, | ||
912 | - page: _resolvePage(page, 'off'), | ||
913 | - binding: binding, | ||
914 | - settings: RouteSettings( | ||
915 | - arguments: arguments, | ||
916 | - name: routeName, | ||
917 | - ), | 903 | + return searchDelegate(id).off( |
904 | + page, | ||
905 | + opaque: opaque ?? true, | ||
906 | + transition: transition, | ||
907 | + curve: curve, | ||
908 | + popGesture: popGesture, | ||
909 | + id: id, | ||
918 | routeName: routeName, | 910 | routeName: routeName, |
911 | + arguments: arguments, | ||
912 | + bindings: bindings, | ||
919 | fullscreenDialog: fullscreenDialog, | 913 | fullscreenDialog: fullscreenDialog, |
920 | - popGesture: popGesture ?? defaultPopGesture, | ||
921 | - transition: transition ?? defaultTransition, | ||
922 | - curve: curve ?? defaultTransitionCurve, | ||
923 | - transitionDuration: duration ?? defaultTransitionDuration)); | 914 | + preventDuplicates: preventDuplicates, |
915 | + duration: duration, | ||
916 | + gestureWidth: gestureWidth, | ||
917 | + ); | ||
918 | + } | ||
919 | + | ||
920 | + Future<T?> offUntil<T>( | ||
921 | + Widget Function() page, | ||
922 | + bool Function(GetPage) predicate, [ | ||
923 | + Object? arguments, | ||
924 | + int? id, | ||
925 | + ]) { | ||
926 | + return searchDelegate(id).offUntil( | ||
927 | + page, | ||
928 | + predicate, | ||
929 | + arguments, | ||
930 | + ); | ||
924 | } | 931 | } |
925 | 932 | ||
926 | /// | 933 | /// |
@@ -954,14 +961,14 @@ you can only use widgets and widget functions here'''; | @@ -954,14 +961,14 @@ you can only use widgets and widget functions here'''; | ||
954 | /// By default, GetX will prevent you from push a route that you already in, | 961 | /// By default, GetX will prevent you from push a route that you already in, |
955 | /// if you want to push anyway, set [preventDuplicates] to false | 962 | /// if you want to push anyway, set [preventDuplicates] to false |
956 | Future<T?>? offAll<T>( | 963 | Future<T?>? offAll<T>( |
957 | - dynamic page, { | ||
958 | - RoutePredicate? predicate, | ||
959 | - bool opaque = false, | 964 | + Widget Function() page, { |
965 | + bool Function(GetPage<dynamic>)? predicate, | ||
966 | + bool? opaque, | ||
960 | bool? popGesture, | 967 | bool? popGesture, |
961 | int? id, | 968 | int? id, |
962 | String? routeName, | 969 | String? routeName, |
963 | dynamic arguments, | 970 | dynamic arguments, |
964 | - Binding? binding, | 971 | + List<BindingsInterface>? bindings, |
965 | bool fullscreenDialog = false, | 972 | bool fullscreenDialog = false, |
966 | Transition? transition, | 973 | Transition? transition, |
967 | Curve? curve, | 974 | Curve? curve, |
@@ -970,24 +977,21 @@ you can only use widgets and widget functions here'''; | @@ -970,24 +977,21 @@ you can only use widgets and widget functions here'''; | ||
970 | }) { | 977 | }) { |
971 | routeName ??= "/${page.runtimeType.toString()}"; | 978 | routeName ??= "/${page.runtimeType.toString()}"; |
972 | routeName = _cleanRouteName(routeName); | 979 | routeName = _cleanRouteName(routeName); |
973 | - return global(id).currentState?.pushAndRemoveUntil<T>( | ||
974 | - GetPageRoute<T>( | ||
975 | - opaque: opaque, | ||
976 | - popGesture: popGesture ?? defaultPopGesture, | ||
977 | - page: _resolvePage(page, 'offAll'), | ||
978 | - binding: binding, | ||
979 | - gestureWidth: gestureWidth, | ||
980 | - settings: RouteSettings( | ||
981 | - name: routeName, | 980 | + return searchDelegate(id).offAll<T>( |
981 | + page, | ||
982 | + predicate: predicate, | ||
983 | + opaque: opaque ?? true, | ||
984 | + popGesture: popGesture, | ||
985 | + id: id, | ||
986 | + // routeName routeName, | ||
982 | arguments: arguments, | 987 | arguments: arguments, |
983 | - ), | 988 | + bindings: bindings, |
984 | fullscreenDialog: fullscreenDialog, | 989 | fullscreenDialog: fullscreenDialog, |
985 | - routeName: routeName, | ||
986 | - transition: transition ?? defaultTransition, | ||
987 | - curve: curve ?? defaultTransitionCurve, | ||
988 | - transitionDuration: duration ?? defaultTransitionDuration, | ||
989 | - ), | ||
990 | - predicate ?? (route) => false); | 990 | + transition: transition, |
991 | + curve: curve, | ||
992 | + duration: duration, | ||
993 | + gestureWidth: gestureWidth, | ||
994 | + ); | ||
991 | } | 995 | } |
992 | 996 | ||
993 | /// Takes a route [name] String generated by [to], [off], [offAll] | 997 | /// Takes a route [name] String generated by [to], [off], [offAll] |
@@ -1072,20 +1076,21 @@ you can only use widgets and widget functions here'''; | @@ -1072,20 +1076,21 @@ you can only use widgets and widget functions here'''; | ||
1072 | return _getxController.addKey(newKey); | 1076 | return _getxController.addKey(newKey); |
1073 | } | 1077 | } |
1074 | 1078 | ||
1075 | - GlobalKey<NavigatorState>? nestedKey(dynamic key) { | 1079 | + GetDelegate? nestedKey(dynamic key) { |
1076 | keys.putIfAbsent( | 1080 | keys.putIfAbsent( |
1077 | key, | 1081 | key, |
1078 | - () => GlobalKey<NavigatorState>( | ||
1079 | - debugLabel: 'Getx nested key: ${key.toString()}', | 1082 | + () => GetDelegate( |
1083 | + //debugLabel: 'Getx nested key: ${key.toString()}', | ||
1084 | + pages: [], | ||
1080 | ), | 1085 | ), |
1081 | ); | 1086 | ); |
1082 | return keys[key]; | 1087 | return keys[key]; |
1083 | } | 1088 | } |
1084 | 1089 | ||
1085 | - GlobalKey<NavigatorState> global(int? k) { | ||
1086 | - GlobalKey<NavigatorState> _key; | 1090 | + GetDelegate searchDelegate(int? k) { |
1091 | + GetDelegate _key; | ||
1087 | if (k == null) { | 1092 | if (k == null) { |
1088 | - _key = key; | 1093 | + _key = Get.rootController.rootDelegate; |
1089 | } else { | 1094 | } else { |
1090 | if (!keys.containsKey(k)) { | 1095 | if (!keys.containsKey(k)) { |
1091 | throw 'Route id ($k) not found'; | 1096 | throw 'Route id ($k) not found'; |
@@ -1093,21 +1098,22 @@ you can only use widgets and widget functions here'''; | @@ -1093,21 +1098,22 @@ you can only use widgets and widget functions here'''; | ||
1093 | _key = keys[k]!; | 1098 | _key = keys[k]!; |
1094 | } | 1099 | } |
1095 | 1100 | ||
1096 | - if (_key.currentContext == null && !testMode) { | ||
1097 | - throw """You are trying to use contextless navigation without | ||
1098 | - a GetMaterialApp or Get.key. | ||
1099 | - If you are testing your app, you can use: | ||
1100 | - [Get.testMode = true], or if you are running your app on | ||
1101 | - a physical device or emulator, you must exchange your [MaterialApp] | ||
1102 | - for a [GetMaterialApp]. | ||
1103 | - """; | ||
1104 | - } | 1101 | + // if (_key.listenersLength == 0 && !testMode) { |
1102 | + // throw """You are trying to use contextless navigation without | ||
1103 | + // a GetMaterialApp or Get.key. | ||
1104 | + // If you are testing your app, you can use: | ||
1105 | + // [Get.testMode = true], or if you are running your app on | ||
1106 | + // a physical device or emulator, you must exchange your [MaterialApp] | ||
1107 | + // for a [GetMaterialApp]. | ||
1108 | + // """; | ||
1109 | + // } | ||
1105 | 1110 | ||
1106 | return _key; | 1111 | return _key; |
1107 | } | 1112 | } |
1108 | 1113 | ||
1109 | /// give current arguments | 1114 | /// give current arguments |
1110 | - dynamic get arguments => routing.args; | 1115 | + //dynamic get arguments => routing.args; |
1116 | + dynamic get arguments => _getxController.rootDelegate.arguments(); | ||
1111 | 1117 | ||
1112 | /// give name from current route | 1118 | /// give name from current route |
1113 | String get currentRoute => routing.current; | 1119 | String get currentRoute => routing.current; |
@@ -1225,7 +1231,7 @@ you can only use widgets and widget functions here'''; | @@ -1225,7 +1231,7 @@ you can only use widgets and widget functions here'''; | ||
1225 | 1231 | ||
1226 | GlobalKey<NavigatorState> get key => _getxController.key; | 1232 | GlobalKey<NavigatorState> get key => _getxController.key; |
1227 | 1233 | ||
1228 | - Map<dynamic, GlobalKey<NavigatorState>> get keys => _getxController.keys; | 1234 | + Map<dynamic, GetDelegate> get keys => _getxController.keys; |
1229 | 1235 | ||
1230 | GetMaterialController get rootController => _getxController; | 1236 | GetMaterialController get rootController => _getxController; |
1231 | 1237 | ||
@@ -1250,7 +1256,8 @@ you can only use widgets and widget functions here'''; | @@ -1250,7 +1256,8 @@ you can only use widgets and widget functions here'''; | ||
1250 | 1256 | ||
1251 | Routing get routing => _getxController.routing; | 1257 | Routing get routing => _getxController.routing; |
1252 | 1258 | ||
1253 | - Map<String, String?> get parameters => _getxController.parameters; | 1259 | + Map<String, String?> get parameters => |
1260 | + _getxController.rootDelegate.parameters; | ||
1254 | set parameters(Map<String, String?> newParameters) => | 1261 | set parameters(Map<String, String?> newParameters) => |
1255 | _getxController.parameters = newParameters; | 1262 | _getxController.parameters = newParameters; |
1256 | 1263 | ||
@@ -1280,10 +1287,15 @@ extension NavTwoExt on GetInterface { | @@ -1280,10 +1287,15 @@ extension NavTwoExt on GetInterface { | ||
1280 | static late final _routeTree = ParseRouteTree(routes: []); | 1287 | static late final _routeTree = ParseRouteTree(routes: []); |
1281 | 1288 | ||
1282 | ParseRouteTree get routeTree => _routeTree; | 1289 | ParseRouteTree get routeTree => _routeTree; |
1290 | + | ||
1283 | void addPage(GetPage getPage) { | 1291 | void addPage(GetPage getPage) { |
1284 | routeTree.addRoute(getPage); | 1292 | routeTree.addRoute(getPage); |
1285 | } | 1293 | } |
1286 | 1294 | ||
1295 | + void removePage(GetPage getPage) { | ||
1296 | + routeTree.removeRoute(getPage); | ||
1297 | + } | ||
1298 | + | ||
1287 | /// Casts the stored router delegate to a desired type | 1299 | /// Casts the stored router delegate to a desired type |
1288 | TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() => | 1300 | TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() => |
1289 | routerDelegate as TDelegate?; | 1301 | routerDelegate as TDelegate?; |
@@ -1307,15 +1319,15 @@ extension NavTwoExt on GetInterface { | @@ -1307,15 +1319,15 @@ extension NavTwoExt on GetInterface { | ||
1307 | 1319 | ||
1308 | // static GetDelegate? _delegate; | 1320 | // static GetDelegate? _delegate; |
1309 | 1321 | ||
1310 | - GetDelegate get rootDelegate => createDelegate(); | ||
1311 | - | ||
1312 | GetDelegate createDelegate({ | 1322 | GetDelegate createDelegate({ |
1313 | GetPage<dynamic>? notFoundRoute, | 1323 | GetPage<dynamic>? notFoundRoute, |
1324 | + List<GetPage> pages = const [], | ||
1314 | List<NavigatorObserver>? navigatorObservers, | 1325 | List<NavigatorObserver>? navigatorObservers, |
1315 | TransitionDelegate<dynamic>? transitionDelegate, | 1326 | TransitionDelegate<dynamic>? transitionDelegate, |
1316 | PopMode backButtonPopMode = PopMode.History, | 1327 | PopMode backButtonPopMode = PopMode.History, |
1317 | PreventDuplicateHandlingMode preventDuplicateHandlingMode = | 1328 | PreventDuplicateHandlingMode preventDuplicateHandlingMode = |
1318 | PreventDuplicateHandlingMode.ReorderRoutes, | 1329 | PreventDuplicateHandlingMode.ReorderRoutes, |
1330 | + GlobalKey<NavigatorState>? navigatorKey, | ||
1319 | }) { | 1331 | }) { |
1320 | if (routerDelegate == null) { | 1332 | if (routerDelegate == null) { |
1321 | return routerDelegate = GetDelegate( | 1333 | return routerDelegate = GetDelegate( |
@@ -1324,6 +1336,8 @@ extension NavTwoExt on GetInterface { | @@ -1324,6 +1336,8 @@ extension NavTwoExt on GetInterface { | ||
1324 | transitionDelegate: transitionDelegate, | 1336 | transitionDelegate: transitionDelegate, |
1325 | backButtonPopMode: backButtonPopMode, | 1337 | backButtonPopMode: backButtonPopMode, |
1326 | preventDuplicateHandlingMode: preventDuplicateHandlingMode, | 1338 | preventDuplicateHandlingMode: preventDuplicateHandlingMode, |
1339 | + pages: pages, | ||
1340 | + navigatorKey: navigatorKey, | ||
1327 | ); | 1341 | ); |
1328 | } else { | 1342 | } else { |
1329 | return routerDelegate as GetDelegate; | 1343 | return routerDelegate as GetDelegate; |
1 | -import 'package:flutter/widgets.dart'; | ||
2 | - | ||
3 | -import '../../../get.dart'; | ||
4 | - | ||
5 | -// class GetRouterState extends GetxController { | ||
6 | -// GetRouterState({required this.currentTreeBranch}); | ||
7 | -// final List<GetPage> currentTreeBranch; | ||
8 | -// GetPage? get currentPage => currentTreeBranch.last; | ||
9 | - | ||
10 | -// static GetNavConfig? fromRoute(String route) { | ||
11 | -// final res = Get.routeTree.matchRoute(route); | ||
12 | -// if (res.treeBranch.isEmpty) return null; | ||
13 | -// return GetNavConfig( | ||
14 | -// currentTreeBranch: res.treeBranch, | ||
15 | -// location: route, | ||
16 | -// state: null, | ||
17 | -// ); | ||
18 | -// } | ||
19 | -// } | ||
20 | - | ||
21 | -/// This config enables us to navigate directly to a sub-url | ||
22 | -class GetNavConfig extends RouteInformation { | ||
23 | - final List<GetPage> currentTreeBranch; | ||
24 | - GetPage? get currentPage => currentTreeBranch.last; | ||
25 | - | ||
26 | - GetNavConfig({ | ||
27 | - required this.currentTreeBranch, | ||
28 | - required String? location, | ||
29 | - required Object? state, | ||
30 | - }) : super( | ||
31 | - location: location, | ||
32 | - state: state, | ||
33 | - ); | ||
34 | - | ||
35 | - GetNavConfig copyWith({ | ||
36 | - List<GetPage>? currentTreeBranch, | ||
37 | - required String? location, | ||
38 | - required Object? state, | ||
39 | - }) { | ||
40 | - return GetNavConfig( | ||
41 | - currentTreeBranch: currentTreeBranch ?? this.currentTreeBranch, | ||
42 | - location: location ?? this.location, | ||
43 | - state: state ?? this.state, | ||
44 | - ); | ||
45 | - } | ||
46 | - | ||
47 | - static GetNavConfig? fromRoute(String route) { | ||
48 | - final res = Get.routeTree.matchRoute(route); | ||
49 | - if (res.treeBranch.isEmpty) return null; | ||
50 | - return GetNavConfig( | ||
51 | - currentTreeBranch: res.treeBranch, | ||
52 | - location: route, | ||
53 | - state: null, | ||
54 | - ); | ||
55 | - } | ||
56 | - | ||
57 | - @override | ||
58 | - String toString() => ''' | ||
59 | -======GetNavConfig=====\nlocation: $location\ncurrentTreeBranch: $currentTreeBranch\n======GetNavConfig====='''; | ||
60 | -} |
1 | -import 'dart:async'; | ||
2 | - | ||
3 | -import 'package:flutter/foundation.dart'; | ||
4 | -import 'package:flutter/material.dart'; | ||
5 | - | ||
6 | -import '../../../get.dart'; | ||
7 | -import '../../../get_state_manager/src/simple/list_notifier.dart'; | ||
8 | - | ||
9 | -/// Enables the user to customize the intended pop behavior | ||
10 | -/// | ||
11 | -/// Goes to either the previous history entry or the previous page entry | ||
12 | -/// | ||
13 | -/// e.g. if the user navigates to these pages | ||
14 | -/// 1) /home | ||
15 | -/// 2) /home/products/1234 | ||
16 | -/// | ||
17 | -/// when popping on [History] mode, it will emulate a browser back button. | ||
18 | -/// | ||
19 | -/// so the new history stack will be: | ||
20 | -/// 1) /home | ||
21 | -/// | ||
22 | -/// when popping on [Page] mode, it will only remove the last part of the route | ||
23 | -/// so the new history stack will be: | ||
24 | -/// 1) /home | ||
25 | -/// 2) /home/products | ||
26 | -/// | ||
27 | -/// another pop will change the history stack to: | ||
28 | -/// 1) /home | ||
29 | -enum PopMode { | ||
30 | - History, | ||
31 | - Page, | ||
32 | -} | ||
33 | - | ||
34 | -/// Enables the user to customize the behavior when pushing multiple routes that | ||
35 | -/// shouldn't be duplicates | ||
36 | -enum PreventDuplicateHandlingMode { | ||
37 | - /// Removes the history entries until it reaches the old route | ||
38 | - PopUntilOriginalRoute, | ||
39 | - | ||
40 | - /// Simply don't push the new route | ||
41 | - DoNothing, | ||
42 | - | ||
43 | - /// Recommended - Moves the old route entry to the front | ||
44 | - /// | ||
45 | - /// With this mode, you guarantee there will be only one | ||
46 | - /// route entry for each location | ||
47 | - ReorderRoutes | ||
48 | -} | ||
49 | - | ||
50 | -class GetDelegate extends RouterDelegate<GetNavConfig> | ||
51 | - with ListNotifierSingleMixin { | ||
52 | - final List<GetNavConfig> history = <GetNavConfig>[]; | ||
53 | - final PopMode backButtonPopMode; | ||
54 | - final PreventDuplicateHandlingMode preventDuplicateHandlingMode; | ||
55 | - | ||
56 | - final GetPage notFoundRoute; | ||
57 | - | ||
58 | - final List<NavigatorObserver>? navigatorObservers; | ||
59 | - final TransitionDelegate<dynamic>? transitionDelegate; | ||
60 | - | ||
61 | - final Iterable<GetPage> Function(GetNavConfig currentNavStack)? | ||
62 | - pickPagesForRootNavigator; | ||
63 | - | ||
64 | - GlobalKey<NavigatorState> get navigatorKey => Get.key; | ||
65 | - | ||
66 | - GetDelegate({ | ||
67 | - GetPage? notFoundRoute, | ||
68 | - this.navigatorObservers, | ||
69 | - this.transitionDelegate, | ||
70 | - this.backButtonPopMode = PopMode.History, | ||
71 | - this.preventDuplicateHandlingMode = | ||
72 | - PreventDuplicateHandlingMode.ReorderRoutes, | ||
73 | - this.pickPagesForRootNavigator, | ||
74 | - }) : notFoundRoute = notFoundRoute ?? | ||
75 | - GetPage( | ||
76 | - name: '/404', | ||
77 | - page: () => Scaffold( | ||
78 | - body: Text('Route not found'), | ||
79 | - ), | ||
80 | - ) { | ||
81 | - Get.log('GetDelegate is created !'); | ||
82 | - } | ||
83 | - | ||
84 | - Future<GetNavConfig?> runMiddleware(GetNavConfig config) async { | ||
85 | - final middlewares = config.currentTreeBranch.last.middlewares; | ||
86 | - if (middlewares == null) { | ||
87 | - return config; | ||
88 | - } | ||
89 | - var iterator = config; | ||
90 | - for (var item in middlewares) { | ||
91 | - var redirectRes = await item.redirectDelegate(iterator); | ||
92 | - if (redirectRes == null) return null; | ||
93 | - iterator = redirectRes; | ||
94 | - } | ||
95 | - return iterator; | ||
96 | - } | ||
97 | - | ||
98 | - Future<void> _unsafeHistoryAdd(GetNavConfig config) async { | ||
99 | - final res = await runMiddleware(config); | ||
100 | - if (res == null) return; | ||
101 | - history.add(res); | ||
102 | - } | ||
103 | - | ||
104 | - Future<void> _unsafeHistoryRemove(GetNavConfig config) async { | ||
105 | - var index = history.indexOf(config); | ||
106 | - if (index >= 0) await _unsafeHistoryRemoveAt(index); | ||
107 | - } | ||
108 | - | ||
109 | - Future<GetNavConfig?> _unsafeHistoryRemoveAt(int index) async { | ||
110 | - if (index == history.length - 1 && history.length > 1) { | ||
111 | - //removing WILL update the current route | ||
112 | - final toCheck = history[history.length - 2]; | ||
113 | - final resMiddleware = await runMiddleware(toCheck); | ||
114 | - if (resMiddleware == null) return null; | ||
115 | - history[history.length - 2] = resMiddleware; | ||
116 | - } | ||
117 | - return history.removeAt(index); | ||
118 | - } | ||
119 | - | ||
120 | - T arguments<T>() { | ||
121 | - return currentConfiguration?.currentPage?.arguments as T; | ||
122 | - } | ||
123 | - | ||
124 | - Map<String, String> get parameters { | ||
125 | - return currentConfiguration?.currentPage?.parameters ?? {}; | ||
126 | - } | ||
127 | - | ||
128 | - /// Adds a new history entry and waits for the result | ||
129 | - Future<void> pushHistory( | ||
130 | - GetNavConfig config, { | ||
131 | - bool rebuildStack = true, | ||
132 | - }) async { | ||
133 | - //this changes the currentConfiguration | ||
134 | - await _pushHistory(config); | ||
135 | - if (rebuildStack) { | ||
136 | - refresh(); | ||
137 | - } | ||
138 | - } | ||
139 | - | ||
140 | - Future<void> _removeHistoryEntry(GetNavConfig entry) async { | ||
141 | - await _unsafeHistoryRemove(entry); | ||
142 | - } | ||
143 | - | ||
144 | - Future<void> _pushHistory(GetNavConfig config) async { | ||
145 | - if (config.currentPage!.preventDuplicates) { | ||
146 | - final originalEntryIndex = | ||
147 | - history.indexWhere((element) => element.location == config.location); | ||
148 | - if (originalEntryIndex >= 0) { | ||
149 | - switch (preventDuplicateHandlingMode) { | ||
150 | - case PreventDuplicateHandlingMode.PopUntilOriginalRoute: | ||
151 | - await backUntil(config.location!, popMode: PopMode.Page); | ||
152 | - break; | ||
153 | - case PreventDuplicateHandlingMode.ReorderRoutes: | ||
154 | - await _unsafeHistoryRemoveAt(originalEntryIndex); | ||
155 | - await _unsafeHistoryAdd(config); | ||
156 | - break; | ||
157 | - case PreventDuplicateHandlingMode.DoNothing: | ||
158 | - default: | ||
159 | - break; | ||
160 | - } | ||
161 | - return; | ||
162 | - } | ||
163 | - } | ||
164 | - await _unsafeHistoryAdd(config); | ||
165 | - } | ||
166 | - | ||
167 | - Future<GetNavConfig?> _popHistory() async { | ||
168 | - if (!_canPopHistory()) return null; | ||
169 | - return await _doPopHistory(); | ||
170 | - } | ||
171 | - | ||
172 | - Future<GetNavConfig?> _doPopHistory() async { | ||
173 | - return await _unsafeHistoryRemoveAt(history.length - 1); | ||
174 | - } | ||
175 | - | ||
176 | - Future<GetNavConfig?> _popPage() async { | ||
177 | - if (!_canPopPage()) return null; | ||
178 | - return await _doPopPage(); | ||
179 | - } | ||
180 | - | ||
181 | - Future<GetNavConfig?> _pop(PopMode mode) async { | ||
182 | - switch (mode) { | ||
183 | - case PopMode.History: | ||
184 | - return await _popHistory(); | ||
185 | - case PopMode.Page: | ||
186 | - return await _popPage(); | ||
187 | - default: | ||
188 | - return null; | ||
189 | - } | ||
190 | - } | ||
191 | - | ||
192 | - // returns the popped page | ||
193 | - Future<GetNavConfig?> _doPopPage() async { | ||
194 | - final currentBranch = currentConfiguration?.currentTreeBranch; | ||
195 | - if (currentBranch != null && currentBranch.length > 1) { | ||
196 | - //remove last part only | ||
197 | - final remaining = currentBranch.take(currentBranch.length - 1); | ||
198 | - final prevHistoryEntry = | ||
199 | - history.length > 1 ? history[history.length - 2] : null; | ||
200 | - | ||
201 | - //check if current route is the same as the previous route | ||
202 | - if (prevHistoryEntry != null) { | ||
203 | - //if so, pop the entire history entry | ||
204 | - final newLocation = remaining.last.name; | ||
205 | - final prevLocation = prevHistoryEntry.location; | ||
206 | - if (newLocation == prevLocation) { | ||
207 | - //pop the entire history entry | ||
208 | - return await _popHistory(); | ||
209 | - } | ||
210 | - } | ||
211 | - | ||
212 | - //create a new route with the remaining tree branch | ||
213 | - final res = await _popHistory(); | ||
214 | - await _pushHistory( | ||
215 | - GetNavConfig( | ||
216 | - currentTreeBranch: remaining.toList(), | ||
217 | - location: remaining.last.name, | ||
218 | - state: null, //TOOD: persist state?? | ||
219 | - ), | ||
220 | - ); | ||
221 | - return res; | ||
222 | - } else { | ||
223 | - //remove entire entry | ||
224 | - return await _popHistory(); | ||
225 | - } | ||
226 | - } | ||
227 | - | ||
228 | - Future<GetNavConfig?> popHistory() async { | ||
229 | - return await _popHistory(); | ||
230 | - } | ||
231 | - | ||
232 | - bool _canPopHistory() { | ||
233 | - return history.length > 1; | ||
234 | - } | ||
235 | - | ||
236 | - Future<bool> canPopHistory() { | ||
237 | - return SynchronousFuture(_canPopHistory()); | ||
238 | - } | ||
239 | - | ||
240 | - bool _canPopPage() { | ||
241 | - final currentTreeBranch = currentConfiguration?.currentTreeBranch; | ||
242 | - if (currentTreeBranch == null) return false; | ||
243 | - return currentTreeBranch.length > 1 ? true : _canPopHistory(); | ||
244 | - } | ||
245 | - | ||
246 | - Future<bool> canPopPage() { | ||
247 | - return SynchronousFuture(_canPopPage()); | ||
248 | - } | ||
249 | - | ||
250 | - bool _canPop(PopMode mode) { | ||
251 | - switch (mode) { | ||
252 | - case PopMode.History: | ||
253 | - return _canPopHistory(); | ||
254 | - case PopMode.Page: | ||
255 | - default: | ||
256 | - return _canPopPage(); | ||
257 | - } | ||
258 | - } | ||
259 | - | ||
260 | - /// gets the visual pages from the current history entry | ||
261 | - /// | ||
262 | - /// visual pages must have [GetPage.participatesInRootNavigator] set to true | ||
263 | - Iterable<GetPage> getVisualPages(GetNavConfig currentHistory) { | ||
264 | - final res = currentHistory.currentTreeBranch | ||
265 | - .where((r) => r.participatesInRootNavigator != null); | ||
266 | - if (res.length == 0) { | ||
267 | - //default behavoir, all routes participate in root navigator | ||
268 | - return history.map((e) => e.currentPage!); | ||
269 | - } else { | ||
270 | - //user specified at least one participatesInRootNavigator | ||
271 | - return res | ||
272 | - .where((element) => element.participatesInRootNavigator == true); | ||
273 | - } | ||
274 | - } | ||
275 | - | ||
276 | - @override | ||
277 | - Widget build(BuildContext context) { | ||
278 | - final currentHistory = currentConfiguration; | ||
279 | - final pages = currentHistory == null | ||
280 | - ? <GetPage>[] | ||
281 | - : pickPagesForRootNavigator?.call(currentHistory) ?? | ||
282 | - getVisualPages(currentHistory); | ||
283 | - if (pages.length == 0) return SizedBox.shrink(); | ||
284 | - return GetNavigator( | ||
285 | - key: navigatorKey, | ||
286 | - onPopPage: _onPopVisualRoute, | ||
287 | - pages: pages.toList(), | ||
288 | - observers: [ | ||
289 | - GetObserver(), | ||
290 | - ...?navigatorObservers, | ||
291 | - ], | ||
292 | - transitionDelegate: | ||
293 | - transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(), | ||
294 | - ); | ||
295 | - } | ||
296 | - | ||
297 | - @override | ||
298 | - Future<void> setNewRoutePath(GetNavConfig configuration) async { | ||
299 | - await pushHistory(configuration); | ||
300 | - } | ||
301 | - | ||
302 | - @override | ||
303 | - GetNavConfig? get currentConfiguration { | ||
304 | - if (history.isEmpty) return null; | ||
305 | - final route = history.last; | ||
306 | - return route; | ||
307 | - } | ||
308 | - | ||
309 | - Future<void> toNamed( | ||
310 | - String page, { | ||
311 | - dynamic arguments, | ||
312 | - Map<String, String>? parameters, | ||
313 | - }) async { | ||
314 | - if (parameters != null) { | ||
315 | - final uri = Uri(path: page, queryParameters: parameters); | ||
316 | - page = uri.toString(); | ||
317 | - } | ||
318 | - | ||
319 | - final decoder = Get.routeTree.matchRoute(page, arguments: arguments); | ||
320 | - decoder.replaceArguments(arguments); | ||
321 | - | ||
322 | - if (decoder.route != null) { | ||
323 | - await pushHistory( | ||
324 | - GetNavConfig( | ||
325 | - currentTreeBranch: decoder.treeBranch, | ||
326 | - location: page, | ||
327 | - state: null, //TODO: persist state? | ||
328 | - ), | ||
329 | - ); | ||
330 | - } else { | ||
331 | - await pushHistory( | ||
332 | - GetNavConfig( | ||
333 | - currentTreeBranch: [notFoundRoute], | ||
334 | - location: notFoundRoute.name, | ||
335 | - state: null, //TODO: persist state? | ||
336 | - ), | ||
337 | - ); | ||
338 | - } | ||
339 | - } | ||
340 | - | ||
341 | - //pops the previous route (if there is one) and goes to new route | ||
342 | - Future<void> offNamed( | ||
343 | - String page, { | ||
344 | - dynamic arguments, | ||
345 | - Map<String, String>? parameters, | ||
346 | - PopMode popMode = PopMode.History, | ||
347 | - }) async { | ||
348 | - await popRoute(popMode: popMode); | ||
349 | - return toNamed(page, arguments: arguments, parameters: parameters); | ||
350 | - } | ||
351 | - | ||
352 | - /// Removes routes according to [PopMode] | ||
353 | - /// until it reaches the specifc [fullRoute], | ||
354 | - /// DOES NOT remove the [fullRoute] | ||
355 | - Future<void> backUntil( | ||
356 | - String fullRoute, { | ||
357 | - PopMode popMode = PopMode.History, | ||
358 | - }) async { | ||
359 | - // remove history or page entries until you meet route | ||
360 | - var iterator = currentConfiguration; | ||
361 | - while (_canPop(popMode) && | ||
362 | - iterator != null && | ||
363 | - iterator.location != fullRoute) { | ||
364 | - await _pop(popMode); | ||
365 | - // replace iterator | ||
366 | - iterator = currentConfiguration; | ||
367 | - } | ||
368 | - refresh(); | ||
369 | - } | ||
370 | - | ||
371 | - Future<bool> handlePopupRoutes({ | ||
372 | - Object? result, | ||
373 | - }) async { | ||
374 | - Route? currentRoute; | ||
375 | - navigatorKey.currentState!.popUntil((route) { | ||
376 | - currentRoute = route; | ||
377 | - return true; | ||
378 | - }); | ||
379 | - if (currentRoute is PopupRoute) { | ||
380 | - return await navigatorKey.currentState!.maybePop(result); | ||
381 | - } | ||
382 | - return false; | ||
383 | - } | ||
384 | - | ||
385 | - @override | ||
386 | - Future<bool> popRoute({ | ||
387 | - Object? result, | ||
388 | - PopMode? popMode, | ||
389 | - }) async { | ||
390 | - //Returning false will cause the entire app to be popped. | ||
391 | - final wasPopup = await handlePopupRoutes(result: result); | ||
392 | - if (wasPopup) return true; | ||
393 | - final _popped = await _pop(popMode ?? backButtonPopMode); | ||
394 | - refresh(); | ||
395 | - if (_popped != null) { | ||
396 | - //emulate the old pop with result | ||
397 | - return true; | ||
398 | - } | ||
399 | - return false; | ||
400 | - } | ||
401 | - | ||
402 | - bool _onPopVisualRoute(Route<dynamic> route, dynamic result) { | ||
403 | - final didPop = route.didPop(result); | ||
404 | - if (!didPop) { | ||
405 | - return false; | ||
406 | - } | ||
407 | - final settings = route.settings; | ||
408 | - if (settings is GetPage) { | ||
409 | - final config = history.cast<GetNavConfig?>().firstWhere( | ||
410 | - (element) => element?.currentPage == settings, | ||
411 | - orElse: () => null, | ||
412 | - ); | ||
413 | - if (config != null) { | ||
414 | - _removeHistoryEntry(config); | ||
415 | - } | ||
416 | - } | ||
417 | - refresh(); | ||
418 | - | ||
419 | - return true; | ||
420 | - } | ||
421 | -} |
@@ -62,7 +62,7 @@ class GetCupertinoApp extends StatelessWidget { | @@ -62,7 +62,7 @@ class GetCupertinoApp extends StatelessWidget { | ||
62 | final BackButtonDispatcher? backButtonDispatcher; | 62 | final BackButtonDispatcher? backButtonDispatcher; |
63 | final CupertinoThemeData? theme; | 63 | final CupertinoThemeData? theme; |
64 | final bool useInheritedMediaQuery; | 64 | final bool useInheritedMediaQuery; |
65 | - const GetCupertinoApp({ | 65 | + GetCupertinoApp({ |
66 | Key? key, | 66 | Key? key, |
67 | this.theme, | 67 | this.theme, |
68 | this.navigatorKey, | 68 | this.navigatorKey, |
@@ -115,17 +115,28 @@ class GetCupertinoApp extends StatelessWidget { | @@ -115,17 +115,28 @@ class GetCupertinoApp extends StatelessWidget { | ||
115 | this.highContrastDarkTheme, | 115 | this.highContrastDarkTheme, |
116 | this.actions, | 116 | this.actions, |
117 | }) : routeInformationProvider = null, | 117 | }) : routeInformationProvider = null, |
118 | + backButtonDispatcher = null, | ||
118 | routeInformationParser = null, | 119 | routeInformationParser = null, |
119 | routerDelegate = null, | 120 | routerDelegate = null, |
120 | - backButtonDispatcher = null, | ||
121 | super(key: key); | 121 | super(key: key); |
122 | 122 | ||
123 | + static String _cleanRouteName(String name) { | ||
124 | + name = name.replaceAll('() => ', ''); | ||
125 | + | ||
126 | + /// uncommonent for URL styling. | ||
127 | + // name = name.paramCase!; | ||
128 | + if (!name.startsWith('/')) { | ||
129 | + name = '/$name'; | ||
130 | + } | ||
131 | + return Uri.tryParse(name)?.toString() ?? name; | ||
132 | + } | ||
133 | + | ||
123 | GetCupertinoApp.router({ | 134 | GetCupertinoApp.router({ |
124 | Key? key, | 135 | Key? key, |
125 | this.theme, | 136 | this.theme, |
126 | this.routeInformationProvider, | 137 | this.routeInformationProvider, |
127 | - RouteInformationParser<Object>? routeInformationParser, | ||
128 | - RouterDelegate<Object>? routerDelegate, | 138 | + this.routeInformationParser, |
139 | + this.routerDelegate, | ||
129 | this.backButtonDispatcher, | 140 | this.backButtonDispatcher, |
130 | this.builder, | 141 | this.builder, |
131 | this.title = '', | 142 | this.title = '', |
@@ -165,32 +176,27 @@ class GetCupertinoApp extends StatelessWidget { | @@ -165,32 +176,27 @@ class GetCupertinoApp extends StatelessWidget { | ||
165 | this.transitionDuration, | 176 | this.transitionDuration, |
166 | this.defaultGlobalState, | 177 | this.defaultGlobalState, |
167 | this.getPages, | 178 | this.getPages, |
179 | + this.navigatorObservers, | ||
168 | this.unknownRoute, | 180 | this.unknownRoute, |
169 | - }) : routerDelegate = routerDelegate ??= Get.createDelegate( | ||
170 | - notFoundRoute: unknownRoute, | ||
171 | - ), | ||
172 | - routeInformationParser = | ||
173 | - routeInformationParser ??= Get.createInformationParser( | ||
174 | - initialRoute: getPages?.first.name ?? '/', | ||
175 | - ), | ||
176 | - navigatorObservers = null, | ||
177 | - navigatorKey = null, | 181 | + }) : navigatorKey = null, |
178 | onGenerateRoute = null, | 182 | onGenerateRoute = null, |
179 | home = null, | 183 | home = null, |
180 | onGenerateInitialRoutes = null, | 184 | onGenerateInitialRoutes = null, |
181 | onUnknownRoute = null, | 185 | onUnknownRoute = null, |
182 | routes = null, | 186 | routes = null, |
183 | initialRoute = null, | 187 | initialRoute = null, |
184 | - super(key: key) { | ||
185 | - Get.routerDelegate = routerDelegate; | ||
186 | - Get.routeInformationParser = routeInformationParser; | ||
187 | - } | 188 | + super(key: key); |
188 | 189 | ||
189 | @override | 190 | @override |
190 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 191 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
191 | init: Get.rootController, | 192 | init: Get.rootController, |
192 | dispose: (d) { | 193 | dispose: (d) { |
193 | onDispose?.call(); | 194 | onDispose?.call(); |
195 | + Get.clearRouteTree(); | ||
196 | + Get.clearTranslations(); | ||
197 | + Get.resetRootNavigator(); | ||
198 | + Get.routerDelegate = null; | ||
199 | + Get.routeInformationParser = null; | ||
194 | }, | 200 | }, |
195 | initState: (i) { | 201 | initState: (i) { |
196 | Get.engine!.addPostFrameCallback((timeStamp) { | 202 | Get.engine!.addPostFrameCallback((timeStamp) { |
@@ -211,6 +217,13 @@ class GetCupertinoApp extends StatelessWidget { | @@ -211,6 +217,13 @@ class GetCupertinoApp extends StatelessWidget { | ||
211 | initialBinding?.dependencies(); | 217 | initialBinding?.dependencies(); |
212 | if (getPages != null) { | 218 | if (getPages != null) { |
213 | Get.addPages(getPages!); | 219 | Get.addPages(getPages!); |
220 | + } else { | ||
221 | + Get.addPage( | ||
222 | + GetPage( | ||
223 | + name: _cleanRouteName("/${home.runtimeType}"), | ||
224 | + page: () => home!, | ||
225 | + ), | ||
226 | + ); | ||
214 | } | 227 | } |
215 | 228 | ||
216 | Get.smartManagement = smartManagement; | 229 | Get.smartManagement = smartManagement; |
@@ -226,46 +239,11 @@ class GetCupertinoApp extends StatelessWidget { | @@ -226,46 +239,11 @@ class GetCupertinoApp extends StatelessWidget { | ||
226 | transitionDuration ?? Get.defaultTransitionDuration, | 239 | transitionDuration ?? Get.defaultTransitionDuration, |
227 | ); | 240 | ); |
228 | }, | 241 | }, |
229 | - builder: (_) => routerDelegate != null | ||
230 | - ? CupertinoApp.router( | ||
231 | - routerDelegate: routerDelegate!, | ||
232 | - routeInformationParser: routeInformationParser!, | ||
233 | - backButtonDispatcher: backButtonDispatcher, | ||
234 | - routeInformationProvider: routeInformationProvider, | ||
235 | - key: _.unikey, | ||
236 | - theme: theme, | ||
237 | - builder: defaultBuilder, | ||
238 | - title: title, | ||
239 | - onGenerateTitle: onGenerateTitle, | ||
240 | - color: color, | ||
241 | - locale: Get.locale ?? locale, | ||
242 | - localizationsDelegates: localizationsDelegates, | ||
243 | - localeListResolutionCallback: localeListResolutionCallback, | ||
244 | - localeResolutionCallback: localeResolutionCallback, | ||
245 | - supportedLocales: supportedLocales, | ||
246 | - showPerformanceOverlay: showPerformanceOverlay, | ||
247 | - checkerboardRasterCacheImages: checkerboardRasterCacheImages, | ||
248 | - checkerboardOffscreenLayers: checkerboardOffscreenLayers, | ||
249 | - showSemanticsDebugger: showSemanticsDebugger, | ||
250 | - debugShowCheckedModeBanner: debugShowCheckedModeBanner, | ||
251 | - shortcuts: shortcuts, | ||
252 | - useInheritedMediaQuery: useInheritedMediaQuery, | ||
253 | - ) | ||
254 | - : CupertinoApp( | ||
255 | - key: _.unikey, | ||
256 | - theme: theme, | ||
257 | - navigatorKey: (navigatorKey == null | ||
258 | - ? Get.key | ||
259 | - : Get.addKey(navigatorKey!)), | ||
260 | - home: home, | ||
261 | - routes: routes ?? const <String, WidgetBuilder>{}, | ||
262 | - initialRoute: initialRoute, | ||
263 | - onGenerateRoute: | ||
264 | - (getPages != null ? generator : onGenerateRoute), | ||
265 | - onGenerateInitialRoutes: (getPages == null || home != null) | ||
266 | - ? onGenerateInitialRoutes | ||
267 | - : initialRoutesGenerate, | ||
268 | - onUnknownRoute: onUnknownRoute, | 242 | + builder: (_) { |
243 | + final routerDelegate = Get.createDelegate( | ||
244 | + pages: getPages ?? [], | ||
245 | + notFoundRoute: unknownRoute, | ||
246 | + navigatorKey: navigatorKey, | ||
269 | navigatorObservers: (navigatorObservers == null | 247 | navigatorObservers: (navigatorObservers == null |
270 | ? <NavigatorObserver>[ | 248 | ? <NavigatorObserver>[ |
271 | GetObserver(routingCallback, Get.routing) | 249 | GetObserver(routingCallback, Get.routing) |
@@ -273,7 +251,20 @@ class GetCupertinoApp extends StatelessWidget { | @@ -273,7 +251,20 @@ class GetCupertinoApp extends StatelessWidget { | ||
273 | : <NavigatorObserver>[ | 251 | : <NavigatorObserver>[ |
274 | GetObserver(routingCallback, Get.routing) | 252 | GetObserver(routingCallback, Get.routing) |
275 | ] | 253 | ] |
276 | - ..addAll(navigatorObservers!)), | 254 | + ..addAll(navigatorObservers!))); |
255 | + final routeInformationParser = Get.createInformationParser( | ||
256 | + initialRoute: initialRoute ?? | ||
257 | + getPages?.first.name ?? | ||
258 | + _cleanRouteName("/${home.runtimeType}"), | ||
259 | + ); | ||
260 | + | ||
261 | + return CupertinoApp.router( | ||
262 | + routerDelegate: routerDelegate, | ||
263 | + routeInformationParser: routeInformationParser, | ||
264 | + backButtonDispatcher: backButtonDispatcher, | ||
265 | + routeInformationProvider: routeInformationProvider, | ||
266 | + key: _.unikey, | ||
267 | + theme: theme, | ||
277 | builder: defaultBuilder, | 268 | builder: defaultBuilder, |
278 | title: title, | 269 | title: title, |
279 | onGenerateTitle: onGenerateTitle, | 270 | onGenerateTitle: onGenerateTitle, |
@@ -290,8 +281,8 @@ class GetCupertinoApp extends StatelessWidget { | @@ -290,8 +281,8 @@ class GetCupertinoApp extends StatelessWidget { | ||
290 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, | 281 | debugShowCheckedModeBanner: debugShowCheckedModeBanner, |
291 | shortcuts: shortcuts, | 282 | shortcuts: shortcuts, |
292 | useInheritedMediaQuery: useInheritedMediaQuery, | 283 | useInheritedMediaQuery: useInheritedMediaQuery, |
293 | - // actions: actions, | ||
294 | - ), | 284 | + ); |
285 | + }, | ||
295 | ); | 286 | ); |
296 | 287 | ||
297 | Widget defaultBuilder(BuildContext context, Widget? child) { | 288 | Widget defaultBuilder(BuildContext context, Widget? child) { |
@@ -66,7 +66,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -66,7 +66,7 @@ class GetMaterialApp extends StatelessWidget { | ||
66 | final RouterDelegate<Object>? routerDelegate; | 66 | final RouterDelegate<Object>? routerDelegate; |
67 | final BackButtonDispatcher? backButtonDispatcher; | 67 | final BackButtonDispatcher? backButtonDispatcher; |
68 | final bool useInheritedMediaQuery; | 68 | final bool useInheritedMediaQuery; |
69 | - const GetMaterialApp({ | 69 | + GetMaterialApp({ |
70 | Key? key, | 70 | Key? key, |
71 | this.navigatorKey, | 71 | this.navigatorKey, |
72 | this.scaffoldMessengerKey, | 72 | this.scaffoldMessengerKey, |
@@ -124,17 +124,28 @@ class GetMaterialApp extends StatelessWidget { | @@ -124,17 +124,28 @@ class GetMaterialApp extends StatelessWidget { | ||
124 | this.highContrastDarkTheme, | 124 | this.highContrastDarkTheme, |
125 | this.actions, | 125 | this.actions, |
126 | }) : routeInformationProvider = null, | 126 | }) : routeInformationProvider = null, |
127 | + backButtonDispatcher = null, | ||
127 | routeInformationParser = null, | 128 | routeInformationParser = null, |
128 | routerDelegate = null, | 129 | routerDelegate = null, |
129 | - backButtonDispatcher = null, | ||
130 | super(key: key); | 130 | super(key: key); |
131 | 131 | ||
132 | + static String _cleanRouteName(String name) { | ||
133 | + name = name.replaceAll('() => ', ''); | ||
134 | + | ||
135 | + /// uncommonent for URL styling. | ||
136 | + // name = name.paramCase!; | ||
137 | + if (!name.startsWith('/')) { | ||
138 | + name = '/$name'; | ||
139 | + } | ||
140 | + return Uri.tryParse(name)?.toString() ?? name; | ||
141 | + } | ||
142 | + | ||
132 | GetMaterialApp.router({ | 143 | GetMaterialApp.router({ |
133 | Key? key, | 144 | Key? key, |
134 | this.routeInformationProvider, | 145 | this.routeInformationProvider, |
135 | this.scaffoldMessengerKey, | 146 | this.scaffoldMessengerKey, |
136 | - RouteInformationParser<Object>? routeInformationParser, | ||
137 | - RouterDelegate<Object>? routerDelegate, | 147 | + this.routeInformationParser, |
148 | + this.routerDelegate, | ||
138 | this.backButtonDispatcher, | 149 | this.backButtonDispatcher, |
139 | this.builder, | 150 | this.builder, |
140 | this.title = '', | 151 | this.title = '', |
@@ -181,33 +192,29 @@ class GetMaterialApp extends StatelessWidget { | @@ -181,33 +192,29 @@ class GetMaterialApp extends StatelessWidget { | ||
181 | this.getPages, | 192 | this.getPages, |
182 | this.navigatorObservers, | 193 | this.navigatorObservers, |
183 | this.unknownRoute, | 194 | this.unknownRoute, |
184 | - }) : routerDelegate = routerDelegate ??= Get.createDelegate( | ||
185 | - notFoundRoute: unknownRoute, | ||
186 | - ), | ||
187 | - routeInformationParser = | ||
188 | - routeInformationParser ??= Get.createInformationParser( | ||
189 | - initialRoute: getPages?.first.name ?? '/', | ||
190 | - ), | ||
191 | - //navigatorObservers = null, | ||
192 | - navigatorKey = null, | 195 | + }) : navigatorKey = null, |
193 | onGenerateRoute = null, | 196 | onGenerateRoute = null, |
194 | home = null, | 197 | home = null, |
195 | onGenerateInitialRoutes = null, | 198 | onGenerateInitialRoutes = null, |
196 | onUnknownRoute = null, | 199 | onUnknownRoute = null, |
197 | routes = null, | 200 | routes = null, |
198 | initialRoute = null, | 201 | initialRoute = null, |
199 | - super(key: key) { | ||
200 | - Get.routerDelegate = routerDelegate; | ||
201 | - Get.routeInformationParser = routeInformationParser; | ||
202 | - } | 202 | + super(key: key); |
203 | 203 | ||
204 | @override | 204 | @override |
205 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 205 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
206 | init: Get.rootController, | 206 | init: Get.rootController, |
207 | dispose: (d) { | 207 | dispose: (d) { |
208 | onDispose?.call(); | 208 | onDispose?.call(); |
209 | + Get.clearRouteTree(); | ||
210 | + Get.clearTranslations(); | ||
211 | + Get.resetRootNavigator(); | ||
212 | + Get.routerDelegate = null; | ||
213 | + Get.routeInformationParser = null; | ||
209 | }, | 214 | }, |
210 | initState: (i) { | 215 | initState: (i) { |
216 | + // Get.routerDelegate = routerDelegate; | ||
217 | + // Get.routeInformationParser = routeInformationParser; | ||
211 | Get.engine!.addPostFrameCallback((timeStamp) { | 218 | Get.engine!.addPostFrameCallback((timeStamp) { |
212 | onReady?.call(); | 219 | onReady?.call(); |
213 | }); | 220 | }); |
@@ -226,6 +233,13 @@ class GetMaterialApp extends StatelessWidget { | @@ -226,6 +233,13 @@ class GetMaterialApp extends StatelessWidget { | ||
226 | initialBinding?.dependencies(); | 233 | initialBinding?.dependencies(); |
227 | if (getPages != null) { | 234 | if (getPages != null) { |
228 | Get.addPages(getPages!); | 235 | Get.addPages(getPages!); |
236 | + } else { | ||
237 | + Get.addPage( | ||
238 | + GetPage( | ||
239 | + name: _cleanRouteName("/${home.runtimeType}"), | ||
240 | + page: () => home!, | ||
241 | + ), | ||
242 | + ); | ||
229 | } | 243 | } |
230 | 244 | ||
231 | //Get.setDefaultDelegate(routerDelegate); | 245 | //Get.setDefaultDelegate(routerDelegate); |
@@ -242,10 +256,23 @@ class GetMaterialApp extends StatelessWidget { | @@ -242,10 +256,23 @@ class GetMaterialApp extends StatelessWidget { | ||
242 | transitionDuration ?? Get.defaultTransitionDuration, | 256 | transitionDuration ?? Get.defaultTransitionDuration, |
243 | ); | 257 | ); |
244 | }, | 258 | }, |
245 | - builder: (_) => routerDelegate != null | ||
246 | - ? MaterialApp.router( | ||
247 | - routerDelegate: routerDelegate!, | ||
248 | - routeInformationParser: routeInformationParser!, | 259 | + builder: (_) { |
260 | + final routerDelegate = Get.createDelegate( | ||
261 | + pages: getPages ?? [], | ||
262 | + notFoundRoute: unknownRoute, | ||
263 | + navigatorKey: navigatorKey, | ||
264 | + navigatorObservers: (navigatorObservers == null | ||
265 | + ? <NavigatorObserver>[GetObserver(routingCallback, Get.routing)] | ||
266 | + : <NavigatorObserver>[GetObserver(routingCallback, Get.routing)] | ||
267 | + ..addAll(navigatorObservers!))); | ||
268 | + final routeInformationParser = Get.createInformationParser( | ||
269 | + initialRoute: initialRoute ?? | ||
270 | + getPages?.first.name ?? | ||
271 | + _cleanRouteName("/${home.runtimeType}"), | ||
272 | + ); | ||
273 | + return MaterialApp.router( | ||
274 | + routerDelegate: routerDelegate, | ||
275 | + routeInformationParser: routeInformationParser, | ||
249 | backButtonDispatcher: backButtonDispatcher, | 276 | backButtonDispatcher: backButtonDispatcher, |
250 | routeInformationProvider: routeInformationProvider, | 277 | routeInformationProvider: routeInformationProvider, |
251 | key: _.unikey, | 278 | key: _.unikey, |
@@ -254,12 +281,10 @@ class GetMaterialApp extends StatelessWidget { | @@ -254,12 +281,10 @@ class GetMaterialApp extends StatelessWidget { | ||
254 | onGenerateTitle: onGenerateTitle, | 281 | onGenerateTitle: onGenerateTitle, |
255 | color: color, | 282 | color: color, |
256 | theme: _.theme ?? theme ?? ThemeData.fallback(), | 283 | theme: _.theme ?? theme ?? ThemeData.fallback(), |
257 | - darkTheme: | ||
258 | - _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), | 284 | + darkTheme: _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), |
259 | themeMode: _.themeMode ?? themeMode, | 285 | themeMode: _.themeMode ?? themeMode, |
260 | locale: Get.locale ?? locale, | 286 | locale: Get.locale ?? locale, |
261 | - scaffoldMessengerKey: | ||
262 | - scaffoldMessengerKey ?? _.scaffoldMessengerKey, | 287 | + scaffoldMessengerKey: scaffoldMessengerKey ?? _.scaffoldMessengerKey, |
263 | localizationsDelegates: localizationsDelegates, | 288 | localizationsDelegates: localizationsDelegates, |
264 | localeListResolutionCallback: localeListResolutionCallback, | 289 | localeListResolutionCallback: localeListResolutionCallback, |
265 | localeResolutionCallback: localeResolutionCallback, | 290 | localeResolutionCallback: localeResolutionCallback, |
@@ -273,56 +298,8 @@ class GetMaterialApp extends StatelessWidget { | @@ -273,56 +298,8 @@ class GetMaterialApp extends StatelessWidget { | ||
273 | shortcuts: shortcuts, | 298 | shortcuts: shortcuts, |
274 | scrollBehavior: scrollBehavior, | 299 | scrollBehavior: scrollBehavior, |
275 | useInheritedMediaQuery: useInheritedMediaQuery, | 300 | useInheritedMediaQuery: useInheritedMediaQuery, |
276 | - ) | ||
277 | - : MaterialApp( | ||
278 | - key: _.unikey, | ||
279 | - navigatorKey: (navigatorKey == null | ||
280 | - ? Get.key | ||
281 | - : Get.addKey(navigatorKey!)), | ||
282 | - scaffoldMessengerKey: | ||
283 | - scaffoldMessengerKey ?? _.scaffoldMessengerKey, | ||
284 | - home: home, | ||
285 | - routes: routes ?? const <String, WidgetBuilder>{}, | ||
286 | - initialRoute: initialRoute, | ||
287 | - onGenerateRoute: | ||
288 | - (getPages != null ? generator : onGenerateRoute), | ||
289 | - onGenerateInitialRoutes: (getPages == null || home != null) | ||
290 | - ? onGenerateInitialRoutes | ||
291 | - : initialRoutesGenerate, | ||
292 | - onUnknownRoute: onUnknownRoute, | ||
293 | - navigatorObservers: (navigatorObservers == null | ||
294 | - ? <NavigatorObserver>[ | ||
295 | - GetObserver(routingCallback, Get.routing) | ||
296 | - ] | ||
297 | - : <NavigatorObserver>[ | ||
298 | - GetObserver(routingCallback, Get.routing) | ||
299 | - ] | ||
300 | - ..addAll(navigatorObservers!)), | ||
301 | - builder: defaultBuilder, | ||
302 | - title: title, | ||
303 | - onGenerateTitle: onGenerateTitle, | ||
304 | - color: color, | ||
305 | - theme: _.theme ?? theme ?? ThemeData.fallback(), | ||
306 | - darkTheme: | ||
307 | - _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), | ||
308 | - themeMode: _.themeMode ?? themeMode, | ||
309 | - locale: Get.locale ?? locale, | ||
310 | - localizationsDelegates: localizationsDelegates, | ||
311 | - localeListResolutionCallback: localeListResolutionCallback, | ||
312 | - localeResolutionCallback: localeResolutionCallback, | ||
313 | - supportedLocales: supportedLocales, | ||
314 | - debugShowMaterialGrid: debugShowMaterialGrid, | ||
315 | - showPerformanceOverlay: showPerformanceOverlay, | ||
316 | - checkerboardRasterCacheImages: checkerboardRasterCacheImages, | ||
317 | - checkerboardOffscreenLayers: checkerboardOffscreenLayers, | ||
318 | - showSemanticsDebugger: showSemanticsDebugger, | ||
319 | - debugShowCheckedModeBanner: debugShowCheckedModeBanner, | ||
320 | - shortcuts: shortcuts, | ||
321 | - scrollBehavior: scrollBehavior, | ||
322 | - useInheritedMediaQuery: useInheritedMediaQuery, | ||
323 | - // actions: actions, | ||
324 | - ), | ||
325 | ); | 301 | ); |
302 | + }); | ||
326 | 303 | ||
327 | Widget defaultBuilder(BuildContext context, Widget? child) { | 304 | Widget defaultBuilder(BuildContext context, Widget? child) { |
328 | return Directionality( | 305 | return Directionality( |
@@ -340,12 +317,12 @@ class GetMaterialApp extends StatelessWidget { | @@ -340,12 +317,12 @@ class GetMaterialApp extends StatelessWidget { | ||
340 | return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); | 317 | return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); |
341 | } | 318 | } |
342 | 319 | ||
343 | - List<Route<dynamic>> initialRoutesGenerate(String name) { | ||
344 | - return [ | ||
345 | - PageRedirect( | ||
346 | - settings: RouteSettings(name: name), | ||
347 | - unknownRoute: unknownRoute, | ||
348 | - ).page() | ||
349 | - ]; | ||
350 | - } | 320 | + // List<Route<dynamic>> initialRoutesGenerate(String name) { |
321 | + // return [ | ||
322 | + // PageRedirect( | ||
323 | + // settings: RouteSettings(name: name), | ||
324 | + // unknownRoute: unknownRoute, | ||
325 | + // ).page() | ||
326 | + // ]; | ||
327 | + // } | ||
351 | } | 328 | } |
@@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; | @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; | ||
2 | 2 | ||
3 | import '../../../get.dart'; | 3 | import '../../../get.dart'; |
4 | 4 | ||
5 | -class GetMaterialController extends SuperController { | 5 | +class GetMaterialController extends FullLifeCycleController { |
6 | + static GetMaterialController get to => Get.find(); | ||
7 | + | ||
6 | bool testMode = false; | 8 | bool testMode = false; |
7 | Key? unikey; | 9 | Key? unikey; |
8 | ThemeData? theme; | 10 | ThemeData? theme; |
@@ -28,14 +30,14 @@ class GetMaterialController extends SuperController { | @@ -28,14 +30,14 @@ class GetMaterialController extends SuperController { | ||
28 | 30 | ||
29 | CustomTransition? customTransition; | 31 | CustomTransition? customTransition; |
30 | 32 | ||
31 | - var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default'); | 33 | + Map<dynamic, GetDelegate> keys = {}; |
32 | 34 | ||
33 | - Map<dynamic, GlobalKey<NavigatorState>> keys = {}; | 35 | + GlobalKey<NavigatorState> get key => rootDelegate.navigatorKey; |
34 | 36 | ||
35 | - GlobalKey<NavigatorState> get key => _key; | 37 | + GetDelegate get rootDelegate => Get.createDelegate(); |
36 | 38 | ||
37 | GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { | 39 | GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { |
38 | - _key = newKey; | 40 | + rootDelegate.navigatorKey = newKey; |
39 | return key; | 41 | return key; |
40 | } | 42 | } |
41 | 43 | ||
@@ -49,18 +51,6 @@ class GetMaterialController extends SuperController { | @@ -49,18 +51,6 @@ class GetMaterialController extends SuperController { | ||
49 | }); | 51 | }); |
50 | } | 52 | } |
51 | 53 | ||
52 | - @override | ||
53 | - void onDetached() {} | ||
54 | - | ||
55 | - @override | ||
56 | - void onInactive() {} | ||
57 | - | ||
58 | - @override | ||
59 | - void onPaused() {} | ||
60 | - | ||
61 | - @override | ||
62 | - void onResumed() {} | ||
63 | - | ||
64 | void restartApp() { | 54 | void restartApp() { |
65 | unikey = UniqueKey(); | 55 | unikey = UniqueKey(); |
66 | update(); | 56 | update(); |
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; | @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; | ||
2 | 2 | ||
3 | import '../../../get.dart'; | 3 | import '../../../get.dart'; |
4 | import '../router_report.dart'; | 4 | import '../router_report.dart'; |
5 | -import 'get_transition_mixin.dart'; | ||
6 | 5 | ||
7 | @optionalTypeArgs | 6 | @optionalTypeArgs |
8 | mixin RouteReportMixin<T extends StatefulWidget> on State<T> { | 7 | mixin RouteReportMixin<T extends StatefulWidget> on State<T> { |
@@ -33,10 +32,8 @@ mixin PageRouteReportMixin<T> on Route<T> { | @@ -33,10 +32,8 @@ mixin PageRouteReportMixin<T> on Route<T> { | ||
33 | } | 32 | } |
34 | } | 33 | } |
35 | 34 | ||
36 | -class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> | ||
37 | - with | ||
38 | - GetPageRouteTransitionMixin<T>, | ||
39 | - PageRouteReportMixin { | 35 | +class GetPageRoute<T> extends PageRoute<T> |
36 | + with GetPageRouteTransitionMixin<T>, PageRouteReportMixin { | ||
40 | /// Creates a page route for use in an iOS designed app. | 37 | /// Creates a page route for use in an iOS designed app. |
41 | /// | 38 | /// |
42 | /// The [builder], [maintainState], and [fullscreenDialog] arguments must not | 39 | /// The [builder], [maintainState], and [fullscreenDialog] arguments must not |
@@ -54,7 +51,7 @@ class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> | @@ -54,7 +51,7 @@ class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> | ||
54 | this.customTransition, | 51 | this.customTransition, |
55 | this.barrierDismissible = false, | 52 | this.barrierDismissible = false, |
56 | this.barrierColor, | 53 | this.barrierColor, |
57 | - this.binding, | 54 | + this.bindings, |
58 | this.binds, | 55 | this.binds, |
59 | this.routeName, | 56 | this.routeName, |
60 | this.page, | 57 | this.page, |
@@ -76,7 +73,7 @@ class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> | @@ -76,7 +73,7 @@ class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> | ||
76 | final String? routeName; | 73 | final String? routeName; |
77 | //final String reference; | 74 | //final String reference; |
78 | final CustomTransition? customTransition; | 75 | final CustomTransition? customTransition; |
79 | - final BindingsInterface? binding; | 76 | + final List<BindingsInterface>? bindings; |
80 | final Map<String, String>? parameter; | 77 | final Map<String, String>? parameter; |
81 | final List<Bind>? binds; | 78 | final List<Bind>? binds; |
82 | 79 | ||
@@ -121,11 +118,11 @@ class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> | @@ -121,11 +118,11 @@ class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> | ||
121 | ]; | 118 | ]; |
122 | 119 | ||
123 | final localbindings = [ | 120 | final localbindings = [ |
124 | - if (binding != null) ...<BindingsInterface>[binding!], | 121 | + if (bindings != null) ...bindings!, |
125 | ]; | 122 | ]; |
126 | 123 | ||
127 | final bindingsToBind = middlewareRunner | 124 | final bindingsToBind = middlewareRunner |
128 | - .runOnBindingsStart(binding != null ? localbindings : localbinds); | 125 | + .runOnBindingsStart(bindings != null ? localbindings : localbinds); |
129 | 126 | ||
130 | /// Retrocompatibility workaround, remove this when Bindings api | 127 | /// Retrocompatibility workaround, remove this when Bindings api |
131 | /// have been removed | 128 | /// have been removed |
@@ -2,17 +2,18 @@ import 'package:flutter/foundation.dart'; | @@ -2,17 +2,18 @@ import 'package:flutter/foundation.dart'; | ||
2 | import 'package:flutter/widgets.dart'; | 2 | import 'package:flutter/widgets.dart'; |
3 | 3 | ||
4 | import '../../../get.dart'; | 4 | import '../../../get.dart'; |
5 | +import 'parse_route.dart'; | ||
5 | 6 | ||
6 | -class GetInformationParser extends RouteInformationParser<GetNavConfig> { | 7 | +class GetInformationParser extends RouteInformationParser<RouteDecoder> { |
7 | final String initialRoute; | 8 | final String initialRoute; |
8 | 9 | ||
9 | GetInformationParser({ | 10 | GetInformationParser({ |
10 | - this.initialRoute = '/', | 11 | + required this.initialRoute, |
11 | }) { | 12 | }) { |
12 | Get.log('GetInformationParser is created !'); | 13 | Get.log('GetInformationParser is created !'); |
13 | } | 14 | } |
14 | @override | 15 | @override |
15 | - SynchronousFuture<GetNavConfig> parseRouteInformation( | 16 | + SynchronousFuture<RouteDecoder> parseRouteInformation( |
16 | RouteInformation routeInformation, | 17 | RouteInformation routeInformation, |
17 | ) { | 18 | ) { |
18 | var location = routeInformation.location; | 19 | var location = routeInformation.location; |
@@ -26,22 +27,16 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { | @@ -26,22 +27,16 @@ class GetInformationParser extends RouteInformationParser<GetNavConfig> { | ||
26 | 27 | ||
27 | Get.log('GetInformationParser: route location: $location'); | 28 | Get.log('GetInformationParser: route location: $location'); |
28 | 29 | ||
29 | - final matchResult = Get.routeTree.matchRoute(location ?? initialRoute); | 30 | + final routeName = location ?? initialRoute; |
30 | 31 | ||
31 | - return SynchronousFuture( | ||
32 | - GetNavConfig( | ||
33 | - currentTreeBranch: matchResult.treeBranch, | ||
34 | - location: location, | ||
35 | - state: routeInformation.state, | ||
36 | - ), | ||
37 | - ); | 32 | + return SynchronousFuture(RouteDecoder.fromRoute(routeName)); |
38 | } | 33 | } |
39 | 34 | ||
40 | @override | 35 | @override |
41 | - RouteInformation restoreRouteInformation(GetNavConfig config) { | 36 | + RouteInformation restoreRouteInformation(RouteDecoder config) { |
42 | return RouteInformation( | 37 | return RouteInformation( |
43 | - location: config.location, | ||
44 | - state: config.state, | 38 | + location: config.pageSettings?.name, |
39 | + state: null, | ||
45 | ); | 40 | ); |
46 | } | 41 | } |
47 | } | 42 | } |
1 | +import 'package:flutter/widgets.dart'; | ||
2 | + | ||
3 | +import '../../../get_instance/src/bindings_interface.dart'; | ||
4 | +import '../routes/get_route.dart'; | ||
5 | +import '../routes/transitions_type.dart'; | ||
6 | + | ||
7 | +mixin IGetNavigation { | ||
8 | + Future<T?> to<T>( | ||
9 | + Widget Function() page, { | ||
10 | + bool? opaque, | ||
11 | + Transition? transition, | ||
12 | + Curve? curve, | ||
13 | + Duration? duration, | ||
14 | + int? id, | ||
15 | + String? routeName, | ||
16 | + bool fullscreenDialog = false, | ||
17 | + dynamic arguments, | ||
18 | + List<BindingsInterface>? bindings, | ||
19 | + bool preventDuplicates = true, | ||
20 | + bool? popGesture, | ||
21 | + bool showCupertinoParallax = true, | ||
22 | + double Function(BuildContext context)? gestureWidth, | ||
23 | + }); | ||
24 | + | ||
25 | + Future<T?> off<T>( | ||
26 | + Widget Function() page, { | ||
27 | + bool? opaque, | ||
28 | + Transition? transition, | ||
29 | + Curve? curve, | ||
30 | + Duration? duration, | ||
31 | + int? id, | ||
32 | + String? routeName, | ||
33 | + bool fullscreenDialog = false, | ||
34 | + dynamic arguments, | ||
35 | + List<BindingsInterface>? bindings, | ||
36 | + bool preventDuplicates = true, | ||
37 | + bool? popGesture, | ||
38 | + bool showCupertinoParallax = true, | ||
39 | + double Function(BuildContext context)? gestureWidth, | ||
40 | + }); | ||
41 | + | ||
42 | + Future<T?>? offAll<T>( | ||
43 | + Widget Function() page, { | ||
44 | + bool Function(GetPage route)? predicate, | ||
45 | + bool opaque = true, | ||
46 | + bool? popGesture, | ||
47 | + int? id, | ||
48 | + String? routeName, | ||
49 | + dynamic arguments, | ||
50 | + List<BindingsInterface>? bindings, | ||
51 | + bool fullscreenDialog = false, | ||
52 | + Transition? transition, | ||
53 | + Curve? curve, | ||
54 | + Duration? duration, | ||
55 | + bool showCupertinoParallax = true, | ||
56 | + double Function(BuildContext context)? gestureWidth, | ||
57 | + }); | ||
58 | + | ||
59 | + Future<T?> toNamed<T>( | ||
60 | + String page, { | ||
61 | + dynamic arguments, | ||
62 | + int? id, | ||
63 | + bool preventDuplicates = true, | ||
64 | + Map<String, String>? parameters, | ||
65 | + }); | ||
66 | + | ||
67 | + Future<T?> offNamed<T>( | ||
68 | + String page, { | ||
69 | + dynamic arguments, | ||
70 | + int? id, | ||
71 | + Map<String, String>? parameters, | ||
72 | + }); | ||
73 | + | ||
74 | + Future<T?>? offAllNamed<T>( | ||
75 | + String newRouteName, { | ||
76 | + // bool Function(GetPage route)? predicate, | ||
77 | + dynamic arguments, | ||
78 | + int? id, | ||
79 | + Map<String, String>? parameters, | ||
80 | + }); | ||
81 | + | ||
82 | + Future<T?>? offNamedUntil<T>( | ||
83 | + String page, { | ||
84 | + bool Function(GetPage route)? predicate, | ||
85 | + dynamic arguments, | ||
86 | + int? id, | ||
87 | + Map<String, String>? parameters, | ||
88 | + }); | ||
89 | + | ||
90 | + Future<T?> toNamedAndOffUntil<T>( | ||
91 | + String page, | ||
92 | + bool Function(GetPage) predicate, [ | ||
93 | + Object? data, | ||
94 | + ]); | ||
95 | + | ||
96 | + Future<T?> offUntil<T>( | ||
97 | + Widget Function() page, | ||
98 | + bool Function(GetPage) predicate, [ | ||
99 | + Object? arguments, | ||
100 | + ]); | ||
101 | + | ||
102 | + void back<T>([T? result]); | ||
103 | + | ||
104 | + Future<R?> backAndtoNamed<T, R>(String page, {T? result, Object? arguments}); | ||
105 | + | ||
106 | + void backUntil(bool Function(GetPage) predicate); | ||
107 | + | ||
108 | + void goToUnknownPage([bool clearPages = true]); | ||
109 | +} |
1 | import 'package:flutter/widgets.dart'; | 1 | import 'package:flutter/widgets.dart'; |
2 | + | ||
2 | import '../routes/default_route.dart'; | 3 | import '../routes/default_route.dart'; |
3 | import '../routes/get_route.dart'; | 4 | import '../routes/get_route.dart'; |
4 | 5 | ||
@@ -11,6 +12,7 @@ class GetNavigator extends Navigator { | @@ -11,6 +12,7 @@ class GetNavigator extends Navigator { | ||
11 | bool reportsRouteUpdateToEngine = false, | 12 | bool reportsRouteUpdateToEngine = false, |
12 | TransitionDelegate? transitionDelegate, | 13 | TransitionDelegate? transitionDelegate, |
13 | String? initialRoute, | 14 | String? initialRoute, |
15 | + String? restorationScopeId, | ||
14 | }) : super( | 16 | }) : super( |
15 | //keys should be optional | 17 | //keys should be optional |
16 | key: key, | 18 | key: key, |
@@ -35,6 +37,7 @@ class GetNavigator extends Navigator { | @@ -35,6 +37,7 @@ class GetNavigator extends Navigator { | ||
35 | } | 37 | } |
36 | }, | 38 | }, |
37 | reportsRouteUpdateToEngine: reportsRouteUpdateToEngine, | 39 | reportsRouteUpdateToEngine: reportsRouteUpdateToEngine, |
40 | + restorationScopeId: restorationScopeId, | ||
38 | pages: pages, | 41 | pages: pages, |
39 | observers: [ | 42 | observers: [ |
40 | // GetObserver(), | 43 | // GetObserver(), |
@@ -52,6 +55,7 @@ class GetNavigator extends Navigator { | @@ -52,6 +55,7 @@ class GetNavigator extends Navigator { | ||
52 | bool reportsRouteUpdateToEngine = false, | 55 | bool reportsRouteUpdateToEngine = false, |
53 | TransitionDelegate? transitionDelegate, | 56 | TransitionDelegate? transitionDelegate, |
54 | String? initialRoute, | 57 | String? initialRoute, |
58 | + String? restorationScopeId, | ||
55 | }) : super( | 59 | }) : super( |
56 | //keys should be optional | 60 | //keys should be optional |
57 | key: key, | 61 | key: key, |
@@ -65,6 +69,7 @@ class GetNavigator extends Navigator { | @@ -65,6 +69,7 @@ class GetNavigator extends Navigator { | ||
65 | return true; | 69 | return true; |
66 | }, | 70 | }, |
67 | reportsRouteUpdateToEngine: reportsRouteUpdateToEngine, | 71 | reportsRouteUpdateToEngine: reportsRouteUpdateToEngine, |
72 | + restorationScopeId: restorationScopeId, | ||
68 | pages: pages, | 73 | pages: pages, |
69 | observers: [ | 74 | observers: [ |
70 | // GetObserver(), | 75 | // GetObserver(), |
1 | +import 'dart:async'; | ||
2 | + | ||
1 | import 'package:flutter/cupertino.dart'; | 3 | import 'package:flutter/cupertino.dart'; |
2 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
3 | 5 | ||
4 | -import '../../../get_core/src/get_main.dart'; | ||
5 | import '../../../get_instance/src/bindings_interface.dart'; | 6 | import '../../../get_instance/src/bindings_interface.dart'; |
6 | import '../../../get_state_manager/src/simple/get_state.dart'; | 7 | import '../../../get_state_manager/src/simple/get_state.dart'; |
7 | import '../../get_navigation.dart'; | 8 | import '../../get_navigation.dart'; |
@@ -18,12 +19,14 @@ class GetPage<T> extends Page<T> { | @@ -18,12 +19,14 @@ class GetPage<T> extends Page<T> { | ||
18 | final bool maintainState; | 19 | final bool maintainState; |
19 | final bool opaque; | 20 | final bool opaque; |
20 | final double Function(BuildContext context)? gestureWidth; | 21 | final double Function(BuildContext context)? gestureWidth; |
21 | - final BindingsInterface? binding; | 22 | + //final BindingsInterface? binding; |
23 | + final List<BindingsInterface>? bindings; | ||
22 | final List<Bind> binds; | 24 | final List<Bind> binds; |
23 | final CustomTransition? customTransition; | 25 | final CustomTransition? customTransition; |
24 | final Duration? transitionDuration; | 26 | final Duration? transitionDuration; |
25 | final bool fullscreenDialog; | 27 | final bool fullscreenDialog; |
26 | final bool preventDuplicates; | 28 | final bool preventDuplicates; |
29 | + final Completer<T?>? completer; | ||
27 | // @override | 30 | // @override |
28 | // final LocalKey? key; | 31 | // final LocalKey? key; |
29 | 32 | ||
@@ -42,6 +45,8 @@ class GetPage<T> extends Page<T> { | @@ -42,6 +45,8 @@ class GetPage<T> extends Page<T> { | ||
42 | final GetPage? unknownRoute; | 45 | final GetPage? unknownRoute; |
43 | final bool showCupertinoParallax; | 46 | final bool showCupertinoParallax; |
44 | 47 | ||
48 | + final PreventDuplicateHandlingMode preventDuplicateHandlingMode; | ||
49 | + | ||
45 | GetPage({ | 50 | GetPage({ |
46 | required this.name, | 51 | required this.name, |
47 | required this.page, | 52 | required this.page, |
@@ -56,7 +61,7 @@ class GetPage<T> extends Page<T> { | @@ -56,7 +61,7 @@ class GetPage<T> extends Page<T> { | ||
56 | this.opaque = true, | 61 | this.opaque = true, |
57 | this.transitionDuration, | 62 | this.transitionDuration, |
58 | this.popGesture, | 63 | this.popGesture, |
59 | - this.binding, | 64 | + this.bindings = const [], |
60 | this.binds = const [], | 65 | this.binds = const [], |
61 | this.transition, | 66 | this.transition, |
62 | this.customTransition, | 67 | this.customTransition, |
@@ -67,13 +72,16 @@ class GetPage<T> extends Page<T> { | @@ -67,13 +72,16 @@ class GetPage<T> extends Page<T> { | ||
67 | this.arguments, | 72 | this.arguments, |
68 | this.showCupertinoParallax = true, | 73 | this.showCupertinoParallax = true, |
69 | this.preventDuplicates = true, | 74 | this.preventDuplicates = true, |
75 | + this.preventDuplicateHandlingMode = | ||
76 | + PreventDuplicateHandlingMode.ReorderRoutes, | ||
77 | + this.completer, | ||
70 | }) : path = _nameToRegex(name), | 78 | }) : path = _nameToRegex(name), |
71 | assert(name.startsWith('/'), | 79 | assert(name.startsWith('/'), |
72 | 'It is necessary to start route name [$name] with a slash: /$name'), | 80 | 'It is necessary to start route name [$name] with a slash: /$name'), |
73 | super( | 81 | super( |
74 | key: ValueKey(name), | 82 | key: ValueKey(name), |
75 | name: name, | 83 | name: name, |
76 | - arguments: Get.arguments, | 84 | + // arguments: Get.arguments, |
77 | ); | 85 | ); |
78 | // settings = RouteSettings(name: name, arguments: Get.arguments); | 86 | // settings = RouteSettings(name: name, arguments: Get.arguments); |
79 | 87 | ||
@@ -88,13 +96,14 @@ class GetPage<T> extends Page<T> { | @@ -88,13 +96,14 @@ class GetPage<T> extends Page<T> { | ||
88 | Alignment? alignment, | 96 | Alignment? alignment, |
89 | bool? maintainState, | 97 | bool? maintainState, |
90 | bool? opaque, | 98 | bool? opaque, |
91 | - BindingsInterface? binding, | 99 | + List<BindingsInterface>? bindings, |
100 | + // BindingsInterface? binding, | ||
92 | List<Bind>? binds, | 101 | List<Bind>? binds, |
93 | CustomTransition? customTransition, | 102 | CustomTransition? customTransition, |
94 | Duration? transitionDuration, | 103 | Duration? transitionDuration, |
95 | bool? fullscreenDialog, | 104 | bool? fullscreenDialog, |
96 | RouteSettings? settings, | 105 | RouteSettings? settings, |
97 | - List<GetPage>? children, | 106 | + List<GetPage<T>>? children, |
98 | GetPage? unknownRoute, | 107 | GetPage? unknownRoute, |
99 | List<GetMiddleware>? middlewares, | 108 | List<GetMiddleware>? middlewares, |
100 | bool? preventDuplicates, | 109 | bool? preventDuplicates, |
@@ -102,6 +111,7 @@ class GetPage<T> extends Page<T> { | @@ -102,6 +111,7 @@ class GetPage<T> extends Page<T> { | ||
102 | bool? participatesInRootNavigator, | 111 | bool? participatesInRootNavigator, |
103 | Object? arguments, | 112 | Object? arguments, |
104 | bool? showCupertinoParallax, | 113 | bool? showCupertinoParallax, |
114 | + Completer<T?>? completer, | ||
105 | }) { | 115 | }) { |
106 | return GetPage( | 116 | return GetPage( |
107 | participatesInRootNavigator: | 117 | participatesInRootNavigator: |
@@ -117,7 +127,7 @@ class GetPage<T> extends Page<T> { | @@ -117,7 +127,7 @@ class GetPage<T> extends Page<T> { | ||
117 | alignment: alignment ?? this.alignment, | 127 | alignment: alignment ?? this.alignment, |
118 | maintainState: maintainState ?? this.maintainState, | 128 | maintainState: maintainState ?? this.maintainState, |
119 | opaque: opaque ?? this.opaque, | 129 | opaque: opaque ?? this.opaque, |
120 | - binding: binding ?? this.binding, | 130 | + bindings: bindings ?? this.bindings, |
121 | binds: binds ?? this.binds, | 131 | binds: binds ?? this.binds, |
122 | customTransition: customTransition ?? this.customTransition, | 132 | customTransition: customTransition ?? this.customTransition, |
123 | transitionDuration: transitionDuration ?? this.transitionDuration, | 133 | transitionDuration: transitionDuration ?? this.transitionDuration, |
@@ -129,6 +139,7 @@ class GetPage<T> extends Page<T> { | @@ -129,6 +139,7 @@ class GetPage<T> extends Page<T> { | ||
129 | arguments: arguments ?? this.arguments, | 139 | arguments: arguments ?? this.arguments, |
130 | showCupertinoParallax: | 140 | showCupertinoParallax: |
131 | showCupertinoParallax ?? this.showCupertinoParallax, | 141 | showCupertinoParallax ?? this.showCupertinoParallax, |
142 | + completer: completer ?? this.completer, | ||
132 | ); | 143 | ); |
133 | } | 144 | } |
134 | 145 | ||
@@ -164,6 +175,17 @@ class GetPage<T> extends Page<T> { | @@ -164,6 +175,17 @@ class GetPage<T> extends Page<T> { | ||
164 | 175 | ||
165 | return PathDecoded(RegExp('^$stringPath\$'), keys); | 176 | return PathDecoded(RegExp('^$stringPath\$'), keys); |
166 | } | 177 | } |
178 | + | ||
179 | + @override | ||
180 | + bool operator ==(Object other) { | ||
181 | + if (identical(this, other)) return true; | ||
182 | + return other is GetPage<T> && other.key == key; | ||
183 | + } | ||
184 | + | ||
185 | + @override | ||
186 | + int get hashCode { | ||
187 | + return key.hashCode; | ||
188 | + } | ||
167 | } | 189 | } |
168 | 190 | ||
169 | @immutable | 191 | @immutable |
1 | +import 'dart:async'; | ||
2 | + | ||
3 | +import 'package:flutter/foundation.dart'; | ||
4 | +import 'package:flutter/material.dart'; | ||
5 | + | ||
6 | +import '../../../get_instance/src/bindings_interface.dart'; | ||
7 | +import '../../../get_state_manager/src/simple/list_notifier.dart'; | ||
8 | +import '../../../get_utils/src/platform/platform.dart'; | ||
9 | +import '../../../route_manager.dart'; | ||
10 | + | ||
11 | +/// Enables the user to customize the intended pop behavior | ||
12 | +/// | ||
13 | +/// Goes to either the previous _activePages entry or the previous page entry | ||
14 | +/// | ||
15 | +/// e.g. if the user navigates to these pages | ||
16 | +/// 1) /home | ||
17 | +/// 2) /home/products/1234 | ||
18 | +/// | ||
19 | +/// when popping on [History] mode, it will emulate a browser back button. | ||
20 | +/// | ||
21 | +/// so the new _activePages stack will be: | ||
22 | +/// 1) /home | ||
23 | +/// | ||
24 | +/// when popping on [Page] mode, it will only remove the last part of the route | ||
25 | +/// so the new _activePages stack will be: | ||
26 | +/// 1) /home | ||
27 | +/// 2) /home/products | ||
28 | +/// | ||
29 | +/// another pop will change the _activePages stack to: | ||
30 | +/// 1) /home | ||
31 | +enum PopMode { | ||
32 | + History, | ||
33 | + Page, | ||
34 | +} | ||
35 | + | ||
36 | +/// Enables the user to customize the behavior when pushing multiple routes that | ||
37 | +/// shouldn't be duplicates | ||
38 | +enum PreventDuplicateHandlingMode { | ||
39 | + /// Removes the _activePages entries until it reaches the old route | ||
40 | + PopUntilOriginalRoute, | ||
41 | + | ||
42 | + /// Simply don't push the new route | ||
43 | + DoNothing, | ||
44 | + | ||
45 | + /// Recommended - Moves the old route entry to the front | ||
46 | + /// | ||
47 | + /// With this mode, you guarantee there will be only one | ||
48 | + /// route entry for each location | ||
49 | + ReorderRoutes, | ||
50 | + | ||
51 | + Recreate, | ||
52 | +} | ||
53 | + | ||
54 | +class GetDelegate extends RouterDelegate<RouteDecoder> | ||
55 | + with | ||
56 | + ListNotifierSingleMixin, | ||
57 | + PopNavigatorRouterDelegateMixin<RouteDecoder>, | ||
58 | + IGetNavigation { | ||
59 | + final List<RouteDecoder> _activePages = <RouteDecoder>[]; | ||
60 | + final PopMode backButtonPopMode; | ||
61 | + final PreventDuplicateHandlingMode preventDuplicateHandlingMode; | ||
62 | + | ||
63 | + final GetPage notFoundRoute; | ||
64 | + | ||
65 | + final List<NavigatorObserver>? navigatorObservers; | ||
66 | + final TransitionDelegate<dynamic>? transitionDelegate; | ||
67 | + | ||
68 | + final Iterable<GetPage> Function(RouteDecoder currentNavStack)? | ||
69 | + pickPagesForRootNavigator; | ||
70 | + | ||
71 | + // GlobalKey<NavigatorState> get navigatorKey => Get.key; | ||
72 | + | ||
73 | + @override | ||
74 | + GlobalKey<NavigatorState> navigatorKey; | ||
75 | + | ||
76 | + final String? restorationScopeId; | ||
77 | + | ||
78 | + GetDelegate({ | ||
79 | + GetPage? notFoundRoute, | ||
80 | + this.navigatorObservers, | ||
81 | + this.transitionDelegate, | ||
82 | + this.backButtonPopMode = PopMode.History, | ||
83 | + this.preventDuplicateHandlingMode = | ||
84 | + PreventDuplicateHandlingMode.ReorderRoutes, | ||
85 | + this.pickPagesForRootNavigator, | ||
86 | + this.restorationScopeId, | ||
87 | + bool showHashOnUrl = false, | ||
88 | + GlobalKey<NavigatorState>? navigatorKey, | ||
89 | + required List<GetPage> pages, | ||
90 | + }) : navigatorKey = navigatorKey ?? GlobalKey<NavigatorState>(), | ||
91 | + notFoundRoute = notFoundRoute ??= GetPage( | ||
92 | + name: '/404', | ||
93 | + page: () => Scaffold( | ||
94 | + body: Center(child: Text('Route not found')), | ||
95 | + ), | ||
96 | + ) { | ||
97 | + if (!showHashOnUrl && GetPlatform.isWeb) setUrlStrategy(); | ||
98 | + Get.addPages(pages); | ||
99 | + Get.addPage(notFoundRoute); | ||
100 | + Get.log('GetDelegate is created !'); | ||
101 | + } | ||
102 | + | ||
103 | + Future<RouteDecoder?> runMiddleware(RouteDecoder config) async { | ||
104 | + final middlewares = config.currentTreeBranch.last.middlewares; | ||
105 | + if (middlewares == null) { | ||
106 | + return config; | ||
107 | + } | ||
108 | + var iterator = config; | ||
109 | + for (var item in middlewares) { | ||
110 | + var redirectRes = await item.redirect(iterator); | ||
111 | + if (redirectRes == null) return null; | ||
112 | + iterator = redirectRes; | ||
113 | + } | ||
114 | + return iterator; | ||
115 | + } | ||
116 | + | ||
117 | + Future<void> _unsafeHistoryAdd(RouteDecoder config) async { | ||
118 | + final res = await runMiddleware(config); | ||
119 | + if (res == null) return; | ||
120 | + _activePages.add(res); | ||
121 | + } | ||
122 | + | ||
123 | + Future<T?> _unsafeHistoryRemove<T>(RouteDecoder config, T result) async { | ||
124 | + var index = _activePages.indexOf(config); | ||
125 | + if (index >= 0) return _unsafeHistoryRemoveAt(index, result); | ||
126 | + } | ||
127 | + | ||
128 | + Future<T?> _unsafeHistoryRemoveAt<T>(int index, T result) async { | ||
129 | + if (index == _activePages.length - 1 && _activePages.length > 1) { | ||
130 | + //removing WILL update the current route | ||
131 | + final toCheck = _activePages[_activePages.length - 2]; | ||
132 | + final resMiddleware = await runMiddleware(toCheck); | ||
133 | + if (resMiddleware == null) return null; | ||
134 | + _activePages[_activePages.length - 2] = resMiddleware; | ||
135 | + } | ||
136 | + | ||
137 | + final completer = _activePages.removeAt(index).route?.completer; | ||
138 | + if (completer?.isCompleted == false) completer!.complete(result); | ||
139 | + | ||
140 | + return completer?.future as T?; | ||
141 | + } | ||
142 | + | ||
143 | + T arguments<T>() { | ||
144 | + return currentConfiguration?.pageSettings?.arguments as T; | ||
145 | + } | ||
146 | + | ||
147 | + Map<String, String> get parameters { | ||
148 | + return currentConfiguration?.pageSettings?.params ?? {}; | ||
149 | + } | ||
150 | + | ||
151 | + PageSettings? get pageSettings { | ||
152 | + return currentConfiguration?.pageSettings; | ||
153 | + } | ||
154 | + | ||
155 | + Future<T?> _removeHistoryEntry<T>(RouteDecoder entry, T result) async { | ||
156 | + return _unsafeHistoryRemove<T>(entry, result); | ||
157 | + } | ||
158 | + | ||
159 | + Future<void> _pushHistory(RouteDecoder config) async { | ||
160 | + if (config.route!.preventDuplicates) { | ||
161 | + final originalEntryIndex = _activePages.indexWhere( | ||
162 | + (element) => element.pageSettings?.name == config.pageSettings?.name); | ||
163 | + if (originalEntryIndex >= 0) { | ||
164 | + switch (preventDuplicateHandlingMode) { | ||
165 | + case PreventDuplicateHandlingMode.PopUntilOriginalRoute: | ||
166 | + popModeUntil(config.pageSettings!.name, popMode: PopMode.Page); | ||
167 | + break; | ||
168 | + case PreventDuplicateHandlingMode.ReorderRoutes: | ||
169 | + await _unsafeHistoryRemoveAt(originalEntryIndex, null); | ||
170 | + await _unsafeHistoryAdd(config); | ||
171 | + break; | ||
172 | + case PreventDuplicateHandlingMode.DoNothing: | ||
173 | + default: | ||
174 | + break; | ||
175 | + } | ||
176 | + return; | ||
177 | + } | ||
178 | + } | ||
179 | + await _unsafeHistoryAdd(config); | ||
180 | + } | ||
181 | + | ||
182 | + Future<T?> _popHistory<T>(T result) async { | ||
183 | + if (!_canPopHistory()) return null; | ||
184 | + return await _doPopHistory(result); | ||
185 | + } | ||
186 | + | ||
187 | + Future<T?> _doPopHistory<T>(T result) async { | ||
188 | + return _unsafeHistoryRemoveAt<T>(_activePages.length - 1, result); | ||
189 | + } | ||
190 | + | ||
191 | + Future<T?> _popPage<T>(T result) async { | ||
192 | + if (!_canPopPage()) return null; | ||
193 | + return await _doPopPage(result); | ||
194 | + } | ||
195 | + | ||
196 | + // returns the popped page | ||
197 | + Future<T?> _doPopPage<T>(T result) async { | ||
198 | + final currentBranch = currentConfiguration?.currentTreeBranch; | ||
199 | + if (currentBranch != null && currentBranch.length > 1) { | ||
200 | + //remove last part only | ||
201 | + final remaining = currentBranch.take(currentBranch.length - 1); | ||
202 | + final prevHistoryEntry = _activePages.length > 1 | ||
203 | + ? _activePages[_activePages.length - 2] | ||
204 | + : null; | ||
205 | + | ||
206 | + //check if current route is the same as the previous route | ||
207 | + if (prevHistoryEntry != null) { | ||
208 | + //if so, pop the entire _activePages entry | ||
209 | + final newLocation = remaining.last.name; | ||
210 | + final prevLocation = prevHistoryEntry.pageSettings?.name; | ||
211 | + if (newLocation == prevLocation) { | ||
212 | + //pop the entire _activePages entry | ||
213 | + return await _popHistory(result); | ||
214 | + } | ||
215 | + } | ||
216 | + | ||
217 | + //create a new route with the remaining tree branch | ||
218 | + final res = await _popHistory<T>(result); | ||
219 | + await _pushHistory( | ||
220 | + RouteDecoder( | ||
221 | + remaining.toList(), | ||
222 | + null, | ||
223 | + //TOOD: persist state?? | ||
224 | + ), | ||
225 | + ); | ||
226 | + return res; | ||
227 | + } else { | ||
228 | + //remove entire entry | ||
229 | + return await _popHistory(result); | ||
230 | + } | ||
231 | + } | ||
232 | + | ||
233 | + Future<T?> _pop<T>(PopMode mode, T result) async { | ||
234 | + switch (mode) { | ||
235 | + case PopMode.History: | ||
236 | + return await _popHistory<T>(result); | ||
237 | + case PopMode.Page: | ||
238 | + return await _popPage<T>(result); | ||
239 | + default: | ||
240 | + return null; | ||
241 | + } | ||
242 | + } | ||
243 | + | ||
244 | + Future<T?> popHistory<T>(T result) async { | ||
245 | + return await _popHistory<T>(result); | ||
246 | + } | ||
247 | + | ||
248 | + bool _canPopHistory() { | ||
249 | + return _activePages.length > 1; | ||
250 | + } | ||
251 | + | ||
252 | + Future<bool> canPopHistory() { | ||
253 | + return SynchronousFuture(_canPopHistory()); | ||
254 | + } | ||
255 | + | ||
256 | + bool _canPopPage() { | ||
257 | + final currentTreeBranch = currentConfiguration?.currentTreeBranch; | ||
258 | + if (currentTreeBranch == null) return false; | ||
259 | + return currentTreeBranch.length > 1 ? true : _canPopHistory(); | ||
260 | + } | ||
261 | + | ||
262 | + Future<bool> canPopPage() { | ||
263 | + return SynchronousFuture(_canPopPage()); | ||
264 | + } | ||
265 | + | ||
266 | + bool _canPop(mode) { | ||
267 | + switch (mode) { | ||
268 | + case PopMode.History: | ||
269 | + return _canPopHistory(); | ||
270 | + case PopMode.Page: | ||
271 | + default: | ||
272 | + return _canPopPage(); | ||
273 | + } | ||
274 | + } | ||
275 | + | ||
276 | + /// gets the visual pages from the current _activePages entry | ||
277 | + /// | ||
278 | + /// visual pages must have [GetPage.participatesInRootNavigator] set to true | ||
279 | + Iterable<GetPage> getVisualPages(RouteDecoder? currentHistory) { | ||
280 | + final res = currentHistory!.currentTreeBranch | ||
281 | + .where((r) => r.participatesInRootNavigator != null); | ||
282 | + if (res.length == 0) { | ||
283 | + //default behavoir, all routes participate in root navigator | ||
284 | + return _activePages.map((e) => e.route!); | ||
285 | + } else { | ||
286 | + //user specified at least one participatesInRootNavigator | ||
287 | + return res | ||
288 | + .where((element) => element.participatesInRootNavigator == true); | ||
289 | + } | ||
290 | + } | ||
291 | + | ||
292 | + @override | ||
293 | + Widget build(BuildContext context) { | ||
294 | + final currentHistory = currentConfiguration; | ||
295 | + final pages = currentHistory == null | ||
296 | + ? <GetPage>[] | ||
297 | + : pickPagesForRootNavigator?.call(currentHistory) ?? | ||
298 | + getVisualPages(currentHistory); | ||
299 | + if (pages.length == 0) return SizedBox.shrink(); | ||
300 | + return GetNavigator( | ||
301 | + key: navigatorKey, | ||
302 | + onPopPage: _onPopVisualRoute, | ||
303 | + pages: pages.toList(), | ||
304 | + observers: navigatorObservers, | ||
305 | + transitionDelegate: | ||
306 | + transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(), | ||
307 | + ); | ||
308 | + } | ||
309 | + | ||
310 | + @override | ||
311 | + void goToUnknownPage([bool clearPages = false]) { | ||
312 | + if (clearPages) _activePages.clear(); | ||
313 | + | ||
314 | + final pageSettings = _buildPageSettings(notFoundRoute.name); | ||
315 | + final routeDecoder = _getRouteDecoder(pageSettings); | ||
316 | + | ||
317 | + _push(routeDecoder!); | ||
318 | + } | ||
319 | + | ||
320 | + @protected | ||
321 | + void _popWithResult<T>([T? result]) { | ||
322 | + final completer = _activePages.removeLast().route?.completer; | ||
323 | + if (completer?.isCompleted == false) completer!.complete(result); | ||
324 | + } | ||
325 | + | ||
326 | + @override | ||
327 | + Future<T?> toNamed<T>( | ||
328 | + String page, { | ||
329 | + dynamic arguments, | ||
330 | + int? id, | ||
331 | + bool preventDuplicates = true, | ||
332 | + Map<String, String>? parameters, | ||
333 | + }) async { | ||
334 | + final args = _buildPageSettings(page, arguments); | ||
335 | + final route = _getRouteDecoder<T>(args); | ||
336 | + if (route != null) { | ||
337 | + return _push<T>(route); | ||
338 | + } else { | ||
339 | + goToUnknownPage(); | ||
340 | + } | ||
341 | + } | ||
342 | + | ||
343 | + @override | ||
344 | + Future<T?> to<T>(Widget Function() page, | ||
345 | + {bool? opaque, | ||
346 | + Transition? transition, | ||
347 | + Curve? curve, | ||
348 | + Duration? duration, | ||
349 | + int? id, | ||
350 | + String? routeName, | ||
351 | + bool fullscreenDialog = false, | ||
352 | + dynamic arguments, | ||
353 | + List<BindingsInterface>? bindings, | ||
354 | + bool preventDuplicates = true, | ||
355 | + bool? popGesture, | ||
356 | + bool showCupertinoParallax = true, | ||
357 | + double Function(BuildContext context)? gestureWidth, | ||
358 | + bool rebuildStack = true, | ||
359 | + PreventDuplicateHandlingMode preventDuplicateHandlingMode = | ||
360 | + PreventDuplicateHandlingMode.ReorderRoutes}) async { | ||
361 | + routeName = _cleanRouteName("/${page.runtimeType}"); | ||
362 | + if (preventDuplicateHandlingMode == PreventDuplicateHandlingMode.Recreate) { | ||
363 | + routeName = routeName + page.hashCode.toString(); | ||
364 | + } | ||
365 | + | ||
366 | + final getPage = GetPage<T>( | ||
367 | + name: routeName, | ||
368 | + opaque: opaque ?? true, | ||
369 | + page: page, | ||
370 | + gestureWidth: gestureWidth, | ||
371 | + showCupertinoParallax: showCupertinoParallax, | ||
372 | + popGesture: popGesture ?? Get.defaultPopGesture, | ||
373 | + transition: transition ?? Get.defaultTransition, | ||
374 | + curve: curve ?? Get.defaultTransitionCurve, | ||
375 | + fullscreenDialog: fullscreenDialog, | ||
376 | + bindings: bindings, | ||
377 | + transitionDuration: duration ?? Get.defaultTransitionDuration, | ||
378 | + preventDuplicateHandlingMode: preventDuplicateHandlingMode, | ||
379 | + ); | ||
380 | + | ||
381 | + Get.addPage(getPage); | ||
382 | + final args = _buildPageSettings(routeName, arguments); | ||
383 | + final route = _getRouteDecoder<T>(args); | ||
384 | + final result = await _push<T>( | ||
385 | + route!, | ||
386 | + rebuildStack: rebuildStack, | ||
387 | + preventDuplicateHandlingMode: preventDuplicateHandlingMode, | ||
388 | + ); | ||
389 | + Get.removePage(getPage); | ||
390 | + return result; | ||
391 | + } | ||
392 | + | ||
393 | + @override | ||
394 | + Future<T?> off<T>( | ||
395 | + Widget Function() page, { | ||
396 | + bool? opaque, | ||
397 | + Transition? transition, | ||
398 | + Curve? curve, | ||
399 | + Duration? duration, | ||
400 | + int? id, | ||
401 | + String? routeName, | ||
402 | + bool fullscreenDialog = false, | ||
403 | + dynamic arguments, | ||
404 | + List<BindingsInterface>? bindings, | ||
405 | + bool preventDuplicates = true, | ||
406 | + bool? popGesture, | ||
407 | + bool showCupertinoParallax = true, | ||
408 | + double Function(BuildContext context)? gestureWidth, | ||
409 | + }) async { | ||
410 | + routeName = _cleanRouteName("/${page.runtimeType}"); | ||
411 | + final route = GetPage<T>( | ||
412 | + name: routeName, | ||
413 | + opaque: opaque ?? true, | ||
414 | + page: page, | ||
415 | + gestureWidth: gestureWidth, | ||
416 | + showCupertinoParallax: showCupertinoParallax, | ||
417 | + popGesture: popGesture ?? Get.defaultPopGesture, | ||
418 | + transition: transition ?? Get.defaultTransition, | ||
419 | + curve: curve ?? Get.defaultTransitionCurve, | ||
420 | + fullscreenDialog: fullscreenDialog, | ||
421 | + bindings: bindings, | ||
422 | + transitionDuration: duration ?? Get.defaultTransitionDuration, | ||
423 | + ); | ||
424 | + | ||
425 | + final args = _buildPageSettings(routeName, arguments); | ||
426 | + return _replace(args, route); | ||
427 | + } | ||
428 | + | ||
429 | + @override | ||
430 | + Future<T?>? offAll<T>( | ||
431 | + Widget Function() page, { | ||
432 | + bool Function(GetPage route)? predicate, | ||
433 | + bool opaque = true, | ||
434 | + bool? popGesture, | ||
435 | + int? id, | ||
436 | + String? routeName, | ||
437 | + dynamic arguments, | ||
438 | + List<BindingsInterface>? bindings, | ||
439 | + bool fullscreenDialog = false, | ||
440 | + Transition? transition, | ||
441 | + Curve? curve, | ||
442 | + Duration? duration, | ||
443 | + bool showCupertinoParallax = true, | ||
444 | + double Function(BuildContext context)? gestureWidth, | ||
445 | + }) async { | ||
446 | + routeName = _cleanRouteName("/${page.runtimeType}"); | ||
447 | + final route = GetPage<T>( | ||
448 | + name: routeName, | ||
449 | + opaque: opaque, | ||
450 | + page: page, | ||
451 | + gestureWidth: gestureWidth, | ||
452 | + showCupertinoParallax: showCupertinoParallax, | ||
453 | + popGesture: popGesture ?? Get.defaultPopGesture, | ||
454 | + transition: transition ?? Get.defaultTransition, | ||
455 | + curve: curve ?? Get.defaultTransitionCurve, | ||
456 | + fullscreenDialog: fullscreenDialog, | ||
457 | + bindings: bindings, | ||
458 | + transitionDuration: duration ?? Get.defaultTransitionDuration, | ||
459 | + ); | ||
460 | + | ||
461 | + final args = _buildPageSettings(routeName, arguments); | ||
462 | + | ||
463 | + final newPredicate = predicate ?? (route) => false; | ||
464 | + | ||
465 | + while (_activePages.length > 1 && !newPredicate(_activePages.last.route!)) { | ||
466 | + _popWithResult(); | ||
467 | + } | ||
468 | + | ||
469 | + return _replace(args, route); | ||
470 | + } | ||
471 | + | ||
472 | + @override | ||
473 | + Future<T?>? offAllNamed<T>( | ||
474 | + String page, { | ||
475 | + // bool Function(GetPage route)? predicate, | ||
476 | + dynamic arguments, | ||
477 | + int? id, | ||
478 | + Map<String, String>? parameters, | ||
479 | + }) async { | ||
480 | + final args = _buildPageSettings(page, arguments); | ||
481 | + final route = _getRouteDecoder<T>(args); | ||
482 | + if (route == null) return null; | ||
483 | + | ||
484 | + while (_activePages.length > 1) { | ||
485 | + _activePages.removeLast(); | ||
486 | + } | ||
487 | + | ||
488 | + return _replaceNamed(route); | ||
489 | + } | ||
490 | + | ||
491 | + @override | ||
492 | + Future<T?>? offNamedUntil<T>( | ||
493 | + String page, { | ||
494 | + bool Function(GetPage route)? predicate, | ||
495 | + dynamic arguments, | ||
496 | + int? id, | ||
497 | + Map<String, String>? parameters, | ||
498 | + }) async { | ||
499 | + final args = _buildPageSettings(page, arguments); | ||
500 | + final route = _getRouteDecoder<T>(args); | ||
501 | + if (route == null) return null; | ||
502 | + | ||
503 | + final newPredicate = predicate ?? (route) => false; | ||
504 | + | ||
505 | + while (_activePages.length > 1 && newPredicate(_activePages.last.route!)) { | ||
506 | + _activePages.removeLast(); | ||
507 | + } | ||
508 | + | ||
509 | + return _replaceNamed(route); | ||
510 | + } | ||
511 | + | ||
512 | + @override | ||
513 | + Future<T?> offNamed<T>( | ||
514 | + String page, { | ||
515 | + dynamic arguments, | ||
516 | + int? id, | ||
517 | + Map<String, String>? parameters, | ||
518 | + }) async { | ||
519 | + final args = _buildPageSettings(page, arguments); | ||
520 | + final route = _getRouteDecoder<T>(args); | ||
521 | + if (route == null) return null; | ||
522 | + _popWithResult(); | ||
523 | + return _push<T>(route); | ||
524 | + } | ||
525 | + | ||
526 | + @override | ||
527 | + Future<T?> toNamedAndOffUntil<T>( | ||
528 | + String page, | ||
529 | + bool Function(GetPage) predicate, [ | ||
530 | + Object? data, | ||
531 | + ]) async { | ||
532 | + final arguments = _buildPageSettings(page, data); | ||
533 | + | ||
534 | + final route = _getRouteDecoder<T>(arguments); | ||
535 | + | ||
536 | + if (route == null) return null; | ||
537 | + | ||
538 | + while (_activePages.isNotEmpty && !predicate(_activePages.last.route!)) { | ||
539 | + _popWithResult(); | ||
540 | + } | ||
541 | + | ||
542 | + return _push<T>(route); | ||
543 | + } | ||
544 | + | ||
545 | + @override | ||
546 | + Future<T?> offUntil<T>( | ||
547 | + Widget Function() page, | ||
548 | + bool Function(GetPage) predicate, [ | ||
549 | + Object? arguments, | ||
550 | + ]) async { | ||
551 | + while (_activePages.isNotEmpty && !predicate(_activePages.last.route!)) { | ||
552 | + _popWithResult(); | ||
553 | + } | ||
554 | + | ||
555 | + return to<T>(page, arguments: arguments); | ||
556 | + } | ||
557 | + | ||
558 | + @override | ||
559 | + void removeRoute<T>(String name) { | ||
560 | + _activePages.remove(RouteDecoder.fromRoute(name)); | ||
561 | + } | ||
562 | + | ||
563 | + @override | ||
564 | + void back<T>([T? result]) { | ||
565 | + _checkIfCanBack(); | ||
566 | + _popWithResult<T>(result); | ||
567 | + refresh(); | ||
568 | + } | ||
569 | + | ||
570 | + bool get canBack { | ||
571 | + return _activePages.length > 1; | ||
572 | + } | ||
573 | + | ||
574 | + void _checkIfCanBack() { | ||
575 | + assert(() { | ||
576 | + if (!canBack) { | ||
577 | + final last = _activePages.last; | ||
578 | + final name = last.route?.name; | ||
579 | + throw 'The page $name cannot be popped'; | ||
580 | + } | ||
581 | + return true; | ||
582 | + }()); | ||
583 | + } | ||
584 | + | ||
585 | + @override | ||
586 | + Future<R?> backAndtoNamed<T, R>(String page, | ||
587 | + {T? result, Object? arguments}) async { | ||
588 | + final args = _buildPageSettings(page, arguments); | ||
589 | + final route = _getRouteDecoder<R>(args); | ||
590 | + if (route == null) return null; | ||
591 | + _popWithResult<T>(result); | ||
592 | + return _push<R>(route); | ||
593 | + } | ||
594 | + | ||
595 | + /// Removes routes according to [PopMode] | ||
596 | + /// until it reaches the specifc [fullRoute], | ||
597 | + /// DOES NOT remove the [fullRoute] | ||
598 | + @override | ||
599 | + Future<void> popModeUntil( | ||
600 | + String fullRoute, { | ||
601 | + PopMode popMode = PopMode.History, | ||
602 | + }) async { | ||
603 | + // remove history or page entries until you meet route | ||
604 | + var iterator = currentConfiguration; | ||
605 | + while (_canPop(popMode) && | ||
606 | + iterator != null && | ||
607 | + iterator.pageSettings?.name != fullRoute) { | ||
608 | + await _pop(popMode, null); | ||
609 | + // replace iterator | ||
610 | + iterator = currentConfiguration; | ||
611 | + } | ||
612 | + refresh(); | ||
613 | + } | ||
614 | + | ||
615 | + @override | ||
616 | + void backUntil(bool Function(GetPage) predicate) { | ||
617 | + while (_activePages.length <= 1 && !predicate(_activePages.last.route!)) { | ||
618 | + _popWithResult(); | ||
619 | + } | ||
620 | + | ||
621 | + refresh(); | ||
622 | + } | ||
623 | + | ||
624 | + Future<T?> _replace<T>(PageSettings arguments, GetPage<T> page) async { | ||
625 | + final index = _activePages.length > 1 ? _activePages.length - 1 : 0; | ||
626 | + Get.addPage(page); | ||
627 | + | ||
628 | + final route = _getRouteDecoder(arguments); | ||
629 | + | ||
630 | + final activePage = _configureRouterDecoder<T>(route!, arguments); | ||
631 | + | ||
632 | + _activePages[index] = activePage; | ||
633 | + | ||
634 | + refresh(); | ||
635 | + final result = await activePage.route?.completer?.future as Future<T?>?; | ||
636 | + Get.removePage(page); | ||
637 | + | ||
638 | + return result; | ||
639 | + } | ||
640 | + | ||
641 | + Future<T?> _replaceNamed<T>(RouteDecoder activePage) async { | ||
642 | + final index = _activePages.length > 1 ? _activePages.length - 1 : 0; | ||
643 | + // final activePage = _configureRouterDecoder<T>(page, arguments); | ||
644 | + _activePages[index] = activePage; | ||
645 | + | ||
646 | + refresh(); | ||
647 | + final result = await activePage.route?.completer?.future as Future<T?>?; | ||
648 | + return result; | ||
649 | + } | ||
650 | + | ||
651 | + /// Takes a route [name] String generated by [to], [off], [offAll] | ||
652 | + /// (and similar context navigation methods), cleans the extra chars and | ||
653 | + /// accommodates the format. | ||
654 | + /// TODO: check for a more "appealing" URL naming convention. | ||
655 | + /// `() => MyHomeScreenView` becomes `/my-home-screen-view`. | ||
656 | + String _cleanRouteName(String name) { | ||
657 | + name = name.replaceAll('() => ', ''); | ||
658 | + | ||
659 | + /// uncommonent for URL styling. | ||
660 | + // name = name.paramCase!; | ||
661 | + if (!name.startsWith('/')) { | ||
662 | + name = '/$name'; | ||
663 | + } | ||
664 | + return Uri.tryParse(name)?.toString() ?? name; | ||
665 | + } | ||
666 | + | ||
667 | + PageSettings _buildPageSettings(String page, [Object? data]) { | ||
668 | + var uri = Uri.parse(page); | ||
669 | + return PageSettings(uri, data); | ||
670 | + } | ||
671 | + | ||
672 | + @protected | ||
673 | + RouteDecoder? _getRouteDecoder<T>(PageSettings arguments) { | ||
674 | + var page = arguments.uri.path; | ||
675 | + final parameters = arguments.params; | ||
676 | + if (parameters.isNotEmpty) { | ||
677 | + final uri = Uri(path: page, queryParameters: parameters); | ||
678 | + page = uri.toString(); | ||
679 | + } | ||
680 | + | ||
681 | + final decoder = Get.routeTree.matchRoute(page, arguments: arguments); | ||
682 | + final route = decoder.route; | ||
683 | + if (route == null) return null; | ||
684 | + return _configureRouterDecoder(decoder, arguments); | ||
685 | + } | ||
686 | + | ||
687 | + @protected | ||
688 | + RouteDecoder _configureRouterDecoder<T>( | ||
689 | + RouteDecoder decoder, PageSettings arguments) { | ||
690 | + final parameters = | ||
691 | + arguments.params.isEmpty ? arguments.query : arguments.params; | ||
692 | + if (arguments.params.isEmpty) { | ||
693 | + arguments.params.addAll(arguments.query); | ||
694 | + } | ||
695 | + if (decoder.parameters.isEmpty) { | ||
696 | + decoder.parameters.addAll(parameters); | ||
697 | + } | ||
698 | + | ||
699 | + decoder.route = decoder.route?.copy( | ||
700 | + completer: _activePages.isEmpty ? null : Completer(), | ||
701 | + arguments: arguments, | ||
702 | + parameters: parameters, | ||
703 | + ); | ||
704 | + return decoder; | ||
705 | + } | ||
706 | + | ||
707 | + Future<T?> _push<T>(RouteDecoder activePage, | ||
708 | + {bool rebuildStack = true, | ||
709 | + PreventDuplicateHandlingMode preventDuplicateHandlingMode = | ||
710 | + PreventDuplicateHandlingMode.ReorderRoutes}) async { | ||
711 | + final onStackPage = _activePages.firstWhereOrNull( | ||
712 | + (element) => element.route?.key == activePage.route?.key); | ||
713 | + | ||
714 | + /// There are no duplicate routes in the stack | ||
715 | + if (onStackPage == null) { | ||
716 | + final res = await runMiddleware(activePage); | ||
717 | + _activePages.add(res!); | ||
718 | + } else { | ||
719 | + /// There are duplicate routes, reorder | ||
720 | + switch (preventDuplicateHandlingMode) { | ||
721 | + case PreventDuplicateHandlingMode.DoNothing: | ||
722 | + break; | ||
723 | + case PreventDuplicateHandlingMode.ReorderRoutes: | ||
724 | + _activePages.remove(onStackPage); | ||
725 | + final res = await runMiddleware(onStackPage); | ||
726 | + _activePages.add(res!); | ||
727 | + break; | ||
728 | + case PreventDuplicateHandlingMode.PopUntilOriginalRoute: | ||
729 | + while (_activePages.last == onStackPage) { | ||
730 | + _popWithResult(); | ||
731 | + } | ||
732 | + break; | ||
733 | + case PreventDuplicateHandlingMode.Recreate: | ||
734 | + _activePages.remove(onStackPage); | ||
735 | + final res = await runMiddleware(activePage); | ||
736 | + _activePages.add(res!); | ||
737 | + break; | ||
738 | + default: | ||
739 | + } | ||
740 | + } | ||
741 | + if (rebuildStack) { | ||
742 | + refresh(); | ||
743 | + } | ||
744 | + | ||
745 | + return activePage.route?.completer?.future as Future<T?>?; | ||
746 | + } | ||
747 | + | ||
748 | + @override | ||
749 | + Future<void> setNewRoutePath(RouteDecoder configuration) async { | ||
750 | + final page = configuration.route; | ||
751 | + if (page == null) { | ||
752 | + goToUnknownPage(); | ||
753 | + return; | ||
754 | + } else { | ||
755 | + _push(configuration); | ||
756 | + } | ||
757 | + } | ||
758 | + | ||
759 | + @override | ||
760 | + RouteDecoder? get currentConfiguration { | ||
761 | + if (_activePages.isEmpty) return null; | ||
762 | + final route = _activePages.last; | ||
763 | + return route; | ||
764 | + } | ||
765 | + | ||
766 | + Future<bool> handlePopupRoutes({ | ||
767 | + Object? result, | ||
768 | + }) async { | ||
769 | + Route? currentRoute; | ||
770 | + navigatorKey.currentState!.popUntil((route) { | ||
771 | + currentRoute = route; | ||
772 | + return true; | ||
773 | + }); | ||
774 | + if (currentRoute is PopupRoute) { | ||
775 | + return await navigatorKey.currentState!.maybePop(result); | ||
776 | + } | ||
777 | + return false; | ||
778 | + } | ||
779 | + | ||
780 | + @override | ||
781 | + Future<bool> popRoute({ | ||
782 | + Object? result, | ||
783 | + PopMode? popMode, | ||
784 | + }) async { | ||
785 | + //Returning false will cause the entire app to be popped. | ||
786 | + final wasPopup = await handlePopupRoutes(result: result); | ||
787 | + if (wasPopup) return true; | ||
788 | + final _popped = await _pop(popMode ?? backButtonPopMode, result); | ||
789 | + refresh(); | ||
790 | + if (_popped != null) { | ||
791 | + //emulate the old pop with result | ||
792 | + return true; | ||
793 | + } | ||
794 | + return false; | ||
795 | + } | ||
796 | + | ||
797 | + bool _onPopVisualRoute(Route<dynamic> route, dynamic result) { | ||
798 | + final didPop = route.didPop(result); | ||
799 | + if (!didPop) { | ||
800 | + return false; | ||
801 | + } | ||
802 | + final settings = route.settings; | ||
803 | + if (settings is GetPage) { | ||
804 | + final config = _activePages.cast<RouteDecoder?>().firstWhere( | ||
805 | + (element) => element?.route == settings, | ||
806 | + orElse: () => null, | ||
807 | + ); | ||
808 | + if (config != null) { | ||
809 | + _removeHistoryEntry(config, result); | ||
810 | + } | ||
811 | + } | ||
812 | + refresh(); | ||
813 | + | ||
814 | + return true; | ||
815 | + } | ||
816 | +} |
lib/get_navigation/src/routes/index.dart
0 → 100644
1 | +export 'circular_reveal_clipper.dart'; | ||
2 | +export 'custom_transition.dart'; | ||
3 | +export 'default_route.dart'; | ||
4 | +export 'default_transitions.dart'; | ||
5 | +export 'get_information_parser.dart'; | ||
6 | +export 'get_navigation_interface.dart'; | ||
7 | +export 'get_navigator.dart'; | ||
8 | +export 'get_route.dart'; | ||
9 | +export 'get_router_delegate.dart'; | ||
10 | +export 'get_transition_mixin.dart'; | ||
11 | +export 'modules.dart'; | ||
12 | +export 'observers/route_observer.dart'; | ||
13 | +export 'page_settings.dart'; | ||
14 | +export 'parse_route.dart'; | ||
15 | +export 'route_middleware.dart'; | ||
16 | +export 'route_report.dart'; | ||
17 | +export 'router_outlet.dart'; | ||
18 | +export 'transitions_type.dart'; | ||
19 | +export 'url_strategy/url_strategy.dart'; |
@@ -98,7 +98,7 @@ class GetObserver extends NavigatorObserver { | @@ -98,7 +98,7 @@ class GetObserver extends NavigatorObserver { | ||
98 | } | 98 | } |
99 | 99 | ||
100 | RouterReportManager.instance.reportCurrentRoute(route); | 100 | RouterReportManager.instance.reportCurrentRoute(route); |
101 | - _routeSend?.update((value) { | 101 | + _routeSend!.update((value) { |
102 | // Only PageRoute is allowed to change current value | 102 | // Only PageRoute is allowed to change current value |
103 | if (route is PageRoute) { | 103 | if (route is PageRoute) { |
104 | value.current = newRoute.name ?? ''; | 104 | value.current = newRoute.name ?? ''; |
@@ -216,7 +216,6 @@ class Routing { | @@ -216,7 +216,6 @@ class Routing { | ||
216 | /// This is basically a util for rules about 'what a route is' | 216 | /// This is basically a util for rules about 'what a route is' |
217 | class _RouteData { | 217 | class _RouteData { |
218 | final bool isGetPageRoute; | 218 | final bool isGetPageRoute; |
219 | - //final bool isSnackbar; | ||
220 | final bool isBottomSheet; | 219 | final bool isBottomSheet; |
221 | final bool isDialog; | 220 | final bool isDialog; |
222 | final String? name; | 221 | final String? name; |
@@ -224,7 +223,6 @@ class _RouteData { | @@ -224,7 +223,6 @@ class _RouteData { | ||
224 | _RouteData({ | 223 | _RouteData({ |
225 | required this.name, | 224 | required this.name, |
226 | required this.isGetPageRoute, | 225 | required this.isGetPageRoute, |
227 | - // required this.isSnackbar, | ||
228 | required this.isBottomSheet, | 226 | required this.isBottomSheet, |
229 | required this.isDialog, | 227 | required this.isDialog, |
230 | }); | 228 | }); |
@@ -233,7 +231,6 @@ class _RouteData { | @@ -233,7 +231,6 @@ class _RouteData { | ||
233 | return _RouteData( | 231 | return _RouteData( |
234 | name: _extractRouteName(route), | 232 | name: _extractRouteName(route), |
235 | isGetPageRoute: route is GetPageRoute, | 233 | isGetPageRoute: route is GetPageRoute, |
236 | - // isSnackbar: route is SnackRoute, | ||
237 | isDialog: route is GetDialogRoute, | 234 | isDialog: route is GetDialogRoute, |
238 | isBottomSheet: route is GetModalBottomSheetRoute, | 235 | isBottomSheet: route is GetModalBottomSheetRoute, |
239 | ); | 236 | ); |
1 | +import 'package:flutter/widgets.dart'; | ||
2 | + | ||
3 | +import '../../../route_manager.dart'; | ||
4 | + | ||
5 | +extension PageArgExt on BuildContext { | ||
6 | + RouteSettings? get settings { | ||
7 | + return ModalRoute.of(this)!.settings; | ||
8 | + } | ||
9 | + | ||
10 | + PageSettings? get pageSettings { | ||
11 | + final args = ModalRoute.of(this)?.settings.arguments; | ||
12 | + if (args is PageSettings) { | ||
13 | + return args; | ||
14 | + } | ||
15 | + return null; | ||
16 | + } | ||
17 | + | ||
18 | + dynamic get arguments { | ||
19 | + final args = settings?.arguments; | ||
20 | + if (args is PageSettings) { | ||
21 | + return args.arguments; | ||
22 | + } else { | ||
23 | + return args; | ||
24 | + } | ||
25 | + } | ||
26 | + | ||
27 | + Map<String, String> get params { | ||
28 | + final args = settings?.arguments; | ||
29 | + if (args is PageSettings) { | ||
30 | + return args.params; | ||
31 | + } else { | ||
32 | + return {}; | ||
33 | + } | ||
34 | + } | ||
35 | + | ||
36 | + Router get router { | ||
37 | + return Router.of(this); | ||
38 | + } | ||
39 | + | ||
40 | + String get location { | ||
41 | + final parser = router.routeInformationParser; | ||
42 | + final config = delegate.currentConfiguration; | ||
43 | + return parser?.restoreRouteInformation(config)?.location ?? '/'; | ||
44 | + } | ||
45 | + | ||
46 | + RouterDelegate get delegate { | ||
47 | + return router.routerDelegate; | ||
48 | + } | ||
49 | + | ||
50 | + GetDelegate get navigation { | ||
51 | + return router.routerDelegate as GetDelegate; | ||
52 | + } | ||
53 | +} | ||
54 | + | ||
55 | +class PageSettings extends RouteSettings { | ||
56 | + PageSettings( | ||
57 | + this.uri, [ | ||
58 | + this.arguments, | ||
59 | + ]); | ||
60 | + | ||
61 | + @override | ||
62 | + String get name => '$uri'; | ||
63 | + | ||
64 | + @override | ||
65 | + late final Object? arguments; | ||
66 | + | ||
67 | + final Uri uri; | ||
68 | + | ||
69 | + final params = <String, String>{}; | ||
70 | + | ||
71 | + String get path => uri.path; | ||
72 | + | ||
73 | + List<String> get paths => uri.pathSegments; | ||
74 | + | ||
75 | + Map<String, String> get query => uri.queryParameters; | ||
76 | + | ||
77 | + Map<String, List<String>> get queries => uri.queryParametersAll; | ||
78 | + | ||
79 | + @override | ||
80 | + String toString() => name; | ||
81 | + | ||
82 | + PageSettings copy({ | ||
83 | + Uri? uri, | ||
84 | + Object? arguments, | ||
85 | + }) { | ||
86 | + return PageSettings( | ||
87 | + uri ?? this.uri, | ||
88 | + arguments ?? this.arguments, | ||
89 | + ); | ||
90 | + } | ||
91 | + | ||
92 | + @override | ||
93 | + bool operator ==(Object other) { | ||
94 | + if (identical(this, other)) return true; | ||
95 | + | ||
96 | + return other is PageSettings && | ||
97 | + other.uri == uri && | ||
98 | + other.arguments == arguments; | ||
99 | + } | ||
100 | + | ||
101 | + @override | ||
102 | + int get hashCode => uri.hashCode ^ arguments.hashCode; | ||
103 | +} |
1 | -import '../../get_navigation.dart'; | 1 | +import '../../../route_manager.dart'; |
2 | 2 | ||
3 | class RouteDecoder { | 3 | class RouteDecoder { |
4 | - final List<GetPage> treeBranch; | ||
5 | - GetPage? get route => treeBranch.isEmpty ? null : treeBranch.last; | ||
6 | - final Map<String, String> parameters; | ||
7 | - final Object? arguments; | ||
8 | const RouteDecoder( | 4 | const RouteDecoder( |
9 | - this.treeBranch, | ||
10 | - this.parameters, | ||
11 | - this.arguments, | 5 | + this.currentTreeBranch, |
6 | + this.pageSettings, | ||
12 | ); | 7 | ); |
13 | - void replaceArguments(Object? arguments) { | ||
14 | - final _route = route; | ||
15 | - if (_route != null) { | ||
16 | - final index = treeBranch.indexOf(_route); | ||
17 | - treeBranch[index] = _route.copy(arguments: arguments); | 8 | + final List<GetPage> currentTreeBranch; |
9 | + final PageSettings? pageSettings; | ||
10 | + | ||
11 | + factory RouteDecoder.fromRoute(String location) { | ||
12 | + var uri = Uri.parse(location); | ||
13 | + final args = PageSettings(uri); | ||
14 | + final decoder = Get.routeTree.matchRoute(location, arguments: args); | ||
15 | + decoder.route = decoder.route?.copy( | ||
16 | + completer: null, | ||
17 | + arguments: args, | ||
18 | + parameters: args.params, | ||
19 | + ); | ||
20 | + return decoder; | ||
18 | } | 21 | } |
22 | + | ||
23 | + GetPage? get route => | ||
24 | + currentTreeBranch.isEmpty ? null : currentTreeBranch.last; | ||
25 | + | ||
26 | + GetPage routeOrUnknown(GetPage onUnknow) => | ||
27 | + currentTreeBranch.isEmpty ? onUnknow : currentTreeBranch.last; | ||
28 | + | ||
29 | + set route(GetPage? getPage) { | ||
30 | + if (getPage == null) return; | ||
31 | + if (currentTreeBranch.isEmpty) { | ||
32 | + currentTreeBranch.add(getPage); | ||
33 | + } else { | ||
34 | + currentTreeBranch[currentTreeBranch.length - 1] = getPage; | ||
19 | } | 35 | } |
36 | + } | ||
37 | + | ||
38 | + List<GetPage>? get currentChildrens => route?.children; | ||
20 | 39 | ||
21 | - void replaceParameters(Object? arguments) { | 40 | + Map<String, String> get parameters => pageSettings?.params ?? {}; |
41 | + | ||
42 | + dynamic get args { | ||
43 | + return pageSettings?.arguments; | ||
44 | + } | ||
45 | + | ||
46 | + T? arguments<T>() { | ||
47 | + final args = pageSettings?.arguments; | ||
48 | + if (args is T) { | ||
49 | + return pageSettings?.arguments as T; | ||
50 | + } else { | ||
51 | + return null; | ||
52 | + } | ||
53 | + } | ||
54 | + | ||
55 | + void replaceArguments(Object? arguments) { | ||
22 | final _route = route; | 56 | final _route = route; |
23 | if (_route != null) { | 57 | if (_route != null) { |
24 | - final index = treeBranch.indexOf(_route); | ||
25 | - treeBranch[index] = _route.copy(parameters: parameters); | 58 | + final index = currentTreeBranch.indexOf(_route); |
59 | + currentTreeBranch[index] = _route.copy(arguments: arguments); | ||
26 | } | 60 | } |
27 | } | 61 | } |
28 | } | 62 | } |
@@ -34,7 +68,7 @@ class ParseRouteTree { | @@ -34,7 +68,7 @@ class ParseRouteTree { | ||
34 | 68 | ||
35 | final List<GetPage> routes; | 69 | final List<GetPage> routes; |
36 | 70 | ||
37 | - RouteDecoder matchRoute(String name, {Object? arguments}) { | 71 | + RouteDecoder matchRoute(String name, {PageSettings? arguments}) { |
38 | final uri = Uri.parse(name); | 72 | final uri = Uri.parse(name); |
39 | // /home/profile/123 => home,profile,123 => /,/home,/home/profile,/home/profile/123 | 73 | // /home/profile/123 => home,profile,123 => /,/home,/home/profile,/home/profile/123 |
40 | final split = uri.path.split('/').where((element) => element.isNotEmpty); | 74 | final split = uri.path.split('/').where((element) => element.isNotEmpty); |
@@ -77,28 +111,44 @@ class ParseRouteTree { | @@ -77,28 +111,44 @@ class ParseRouteTree { | ||
77 | ), | 111 | ), |
78 | ) | 112 | ) |
79 | .toList(); | 113 | .toList(); |
114 | + arguments?.params.clear(); | ||
115 | + arguments?.params.addAll(params); | ||
80 | return RouteDecoder( | 116 | return RouteDecoder( |
81 | mappedTreeBranch, | 117 | mappedTreeBranch, |
82 | - params, | ||
83 | arguments, | 118 | arguments, |
84 | ); | 119 | ); |
85 | } | 120 | } |
86 | 121 | ||
122 | + arguments?.params.clear(); | ||
123 | + arguments?.params.addAll(params); | ||
124 | + | ||
87 | //route not found | 125 | //route not found |
88 | return RouteDecoder( | 126 | return RouteDecoder( |
89 | treeBranch.map((e) => e.value).toList(), | 127 | treeBranch.map((e) => e.value).toList(), |
90 | - params, | ||
91 | arguments, | 128 | arguments, |
92 | ); | 129 | ); |
93 | } | 130 | } |
94 | 131 | ||
95 | - void addRoutes(List<GetPage> getPages) { | 132 | + void addRoutes<T>(List<GetPage<T>> getPages) { |
96 | for (final route in getPages) { | 133 | for (final route in getPages) { |
97 | addRoute(route); | 134 | addRoute(route); |
98 | } | 135 | } |
99 | } | 136 | } |
100 | 137 | ||
101 | - void addRoute(GetPage route) { | 138 | + void removeRoutes<T>(List<GetPage<T>> getPages) { |
139 | + for (final route in getPages) { | ||
140 | + removeRoute(route); | ||
141 | + } | ||
142 | + } | ||
143 | + | ||
144 | + void removeRoute<T>(GetPage<T> route) { | ||
145 | + routes.remove(route); | ||
146 | + for (var page in _flattenPage(route)) { | ||
147 | + removeRoute(page); | ||
148 | + } | ||
149 | + } | ||
150 | + | ||
151 | + void addRoute<T>(GetPage<T> route) { | ||
102 | routes.add(route); | 152 | routes.add(route); |
103 | 153 | ||
104 | // Add Page children. | 154 | // Add Page children. |
@@ -152,9 +202,11 @@ class ParseRouteTree { | @@ -152,9 +202,11 @@ class ParseRouteTree { | ||
152 | ); | 202 | ); |
153 | 203 | ||
154 | GetPage? _findRoute(String name) { | 204 | GetPage? _findRoute(String name) { |
155 | - return routes.firstWhereOrNull( | 205 | + final value = routes.firstWhereOrNull( |
156 | (route) => route.path.regex.hasMatch(name), | 206 | (route) => route.path.regex.hasMatch(name), |
157 | ); | 207 | ); |
208 | + | ||
209 | + return value; | ||
158 | } | 210 | } |
159 | 211 | ||
160 | Map<String, String> _parseParams(String path, PathDecoded routePath) { | 212 | Map<String, String> _parseParams(String path, PathDecoded routePath) { |
@@ -177,7 +229,7 @@ class ParseRouteTree { | @@ -177,7 +229,7 @@ class ParseRouteTree { | ||
177 | } | 229 | } |
178 | } | 230 | } |
179 | 231 | ||
180 | -extension FirstWhereExt<T> on List<T> { | 232 | +extension FirstWhereOrNullExt<T> on List<T> { |
181 | /// The first element satisfying [test], or `null` if there are none. | 233 | /// The first element satisfying [test], or `null` if there are none. |
182 | T? firstWhereOrNull(bool Function(T element) test) { | 234 | T? firstWhereOrNull(bool Function(T element) test) { |
183 | for (var element in this) { | 235 | for (var element in this) { |
@@ -20,21 +20,6 @@ abstract class _RouteMiddleware { | @@ -20,21 +20,6 @@ abstract class _RouteMiddleware { | ||
20 | /// {@end-tool} | 20 | /// {@end-tool} |
21 | int? priority; | 21 | int? priority; |
22 | 22 | ||
23 | - /// This function will be called when the page of | ||
24 | - /// the called route is being searched for. | ||
25 | - /// It take RouteSettings as a result an redirect to the new settings or | ||
26 | - /// give it null and there will be no redirecting. | ||
27 | - /// {@tool snippet} | ||
28 | - /// ```dart | ||
29 | - /// GetPage redirect(String route) { | ||
30 | - /// final authService = Get.find<AuthService>(); | ||
31 | - /// return authService.authed.value ? null : RouteSettings(name: '/login'); | ||
32 | - /// } | ||
33 | - /// ``` | ||
34 | - /// {@end-tool} | ||
35 | - RouteSettings? redirect(String route); | ||
36 | - | ||
37 | - /// Similar to [redirect], | ||
38 | /// This function will be called when the router delegate changes the | 23 | /// This function will be called when the router delegate changes the |
39 | /// current route. | 24 | /// current route. |
40 | /// | 25 | /// |
@@ -45,13 +30,13 @@ abstract class _RouteMiddleware { | @@ -45,13 +30,13 @@ abstract class _RouteMiddleware { | ||
45 | /// and no new routes are pushed. | 30 | /// and no new routes are pushed. |
46 | /// {@tool snippet} | 31 | /// {@tool snippet} |
47 | /// ```dart | 32 | /// ```dart |
48 | - /// GetNavConfig? redirect(GetNavConfig route) { | 33 | + /// RouteDecoder? redirect(RouteDecoder route) { |
49 | /// final authService = Get.find<AuthService>(); | 34 | /// final authService = Get.find<AuthService>(); |
50 | - /// return authService.authed.value ? null : RouteSettings(name: '/login'); | 35 | + /// return authService.authed.value ? null : RouteDecoder.fromRoute('/login'); |
51 | /// } | 36 | /// } |
52 | /// ``` | 37 | /// ``` |
53 | /// {@end-tool} | 38 | /// {@end-tool} |
54 | - Future<GetNavConfig?> redirectDelegate(GetNavConfig route); | 39 | + Future<RouteDecoder?> redirect(RouteDecoder route); |
55 | 40 | ||
56 | /// This function will be called when this Page is called | 41 | /// This function will be called when this Page is called |
57 | /// you can use it to change something about the page or give it new page | 42 | /// you can use it to change something about the page or give it new page |
@@ -101,8 +86,8 @@ class GetMiddleware implements _RouteMiddleware { | @@ -101,8 +86,8 @@ class GetMiddleware implements _RouteMiddleware { | ||
101 | 86 | ||
102 | GetMiddleware({this.priority}); | 87 | GetMiddleware({this.priority}); |
103 | 88 | ||
104 | - @override | ||
105 | - RouteSettings? redirect(String? route) => null; | 89 | + // @override |
90 | + // RouteSettings? redirect(String? route) => null; | ||
106 | 91 | ||
107 | @override | 92 | @override |
108 | GetPage? onPageCalled(GetPage? page) => page; | 93 | GetPage? onPageCalled(GetPage? page) => page; |
@@ -120,7 +105,7 @@ class GetMiddleware implements _RouteMiddleware { | @@ -120,7 +105,7 @@ class GetMiddleware implements _RouteMiddleware { | ||
120 | void onPageDispose() {} | 105 | void onPageDispose() {} |
121 | 106 | ||
122 | @override | 107 | @override |
123 | - Future<GetNavConfig?> redirectDelegate(GetNavConfig route) => | 108 | + Future<RouteDecoder?> redirect(RouteDecoder route) => |
124 | SynchronousFuture(route); | 109 | SynchronousFuture(route); |
125 | } | 110 | } |
126 | 111 | ||
@@ -144,17 +129,17 @@ class MiddlewareRunner { | @@ -144,17 +129,17 @@ class MiddlewareRunner { | ||
144 | return page; | 129 | return page; |
145 | } | 130 | } |
146 | 131 | ||
147 | - RouteSettings? runRedirect(String? route) { | ||
148 | - RouteSettings? to; | ||
149 | - for (final element in _getMiddlewares()) { | ||
150 | - to = element.redirect(route); | ||
151 | - if (to != null) { | ||
152 | - break; | ||
153 | - } | ||
154 | - } | ||
155 | - Get.log('Redirect to $to'); | ||
156 | - return to; | ||
157 | - } | 132 | + // RouteSettings? runRedirect(String? route) { |
133 | + // RouteSettings? to; | ||
134 | + // for (final element in _getMiddlewares()) { | ||
135 | + // to = element.redirect(route); | ||
136 | + // if (to != null) { | ||
137 | + // break; | ||
138 | + // } | ||
139 | + // } | ||
140 | + // Get.log('Redirect to $to'); | ||
141 | + // return to; | ||
142 | + // } | ||
158 | 143 | ||
159 | List<R>? runOnBindingsStart<R>(List<R>? bindings) { | 144 | List<R>? runOnBindingsStart<R>(List<R>? bindings) { |
160 | _getMiddlewares().forEach((element) { | 145 | _getMiddlewares().forEach((element) { |
@@ -212,7 +197,7 @@ class PageRedirect { | @@ -212,7 +197,7 @@ class PageRedirect { | ||
212 | showCupertinoParallax: _r.showCupertinoParallax, | 197 | showCupertinoParallax: _r.showCupertinoParallax, |
213 | gestureWidth: _r.gestureWidth, | 198 | gestureWidth: _r.gestureWidth, |
214 | customTransition: _r.customTransition, | 199 | customTransition: _r.customTransition, |
215 | - binding: _r.binding, | 200 | + bindings: _r.bindings, |
216 | binds: _r.binds, | 201 | binds: _r.binds, |
217 | transitionDuration: | 202 | transitionDuration: |
218 | _r.transitionDuration ?? Get.defaultTransitionDuration, | 203 | _r.transitionDuration ?? Get.defaultTransitionDuration, |
@@ -235,13 +220,13 @@ class PageRedirect { | @@ -235,13 +220,13 @@ class PageRedirect { | ||
235 | title: _r.title, | 220 | title: _r.title, |
236 | maintainState: _r.maintainState, | 221 | maintainState: _r.maintainState, |
237 | routeName: _r.name, | 222 | routeName: _r.name, |
238 | - settings: _r, | 223 | + settings: settings, |
239 | curve: _r.curve, | 224 | curve: _r.curve, |
240 | showCupertinoParallax: _r.showCupertinoParallax, | 225 | showCupertinoParallax: _r.showCupertinoParallax, |
241 | gestureWidth: _r.gestureWidth, | 226 | gestureWidth: _r.gestureWidth, |
242 | opaque: _r.opaque, | 227 | opaque: _r.opaque, |
243 | customTransition: _r.customTransition, | 228 | customTransition: _r.customTransition, |
244 | - binding: _r.binding, | 229 | + bindings: _r.bindings, |
245 | binds: _r.binds, | 230 | binds: _r.binds, |
246 | transitionDuration: | 231 | transitionDuration: |
247 | _r.transitionDuration ?? Get.defaultTransitionDuration, | 232 | _r.transitionDuration ?? Get.defaultTransitionDuration, |
@@ -274,19 +259,19 @@ class PageRedirect { | @@ -274,19 +259,19 @@ class PageRedirect { | ||
274 | if (match.route!.middlewares == null || match.route!.middlewares!.isEmpty) { | 259 | if (match.route!.middlewares == null || match.route!.middlewares!.isEmpty) { |
275 | return false; | 260 | return false; |
276 | } | 261 | } |
277 | - final newSettings = runner.runRedirect(settings!.name); | ||
278 | - if (newSettings == null) { | ||
279 | - return false; | ||
280 | - } | ||
281 | - settings = newSettings; | 262 | + // final newSettings = runner.runRedirect(settings!.name); |
263 | + // if (newSettings == null) { | ||
264 | + // return false; | ||
265 | + // } | ||
266 | + // settings = newSettings; | ||
282 | return true; | 267 | return true; |
283 | } | 268 | } |
284 | 269 | ||
285 | void addPageParameter(GetPage route) { | 270 | void addPageParameter(GetPage route) { |
286 | if (route.parameters == null) return; | 271 | if (route.parameters == null) return; |
287 | 272 | ||
288 | - final parameters = Get.parameters; | 273 | + final parameters = Map<String, String?>.from(Get.parameters); |
289 | parameters.addEntries(route.parameters!.entries); | 274 | parameters.addEntries(route.parameters!.entries); |
290 | - Get.parameters = parameters; | 275 | + // Get.parameters = parameters; |
291 | } | 276 | } |
292 | } | 277 | } |
@@ -74,12 +74,12 @@ class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object> | @@ -74,12 +74,12 @@ class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object> | ||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | -class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { | 77 | +class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> { |
78 | GetRouterOutlet({ | 78 | GetRouterOutlet({ |
79 | String? anchorRoute, | 79 | String? anchorRoute, |
80 | required String initialRoute, | 80 | required String initialRoute, |
81 | Iterable<GetPage> Function(Iterable<GetPage> afterAnchor)? filterPages, | 81 | Iterable<GetPage> Function(Iterable<GetPage> afterAnchor)? filterPages, |
82 | - GlobalKey<NavigatorState>? key, | 82 | + // GlobalKey<NavigatorState>? key, |
83 | GetDelegate? delegate, | 83 | GetDelegate? delegate, |
84 | }) : this.pickPages( | 84 | }) : this.pickPages( |
85 | pickPages: (config) { | 85 | pickPages: (config) { |
@@ -102,13 +102,13 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { | @@ -102,13 +102,13 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { | ||
102 | emptyPage: (delegate) => | 102 | emptyPage: (delegate) => |
103 | Get.routeTree.matchRoute(initialRoute).route ?? | 103 | Get.routeTree.matchRoute(initialRoute).route ?? |
104 | delegate.notFoundRoute, | 104 | delegate.notFoundRoute, |
105 | - key: key, | 105 | + key: Get.nestedKey(anchorRoute)?.navigatorKey, |
106 | delegate: delegate, | 106 | delegate: delegate, |
107 | ); | 107 | ); |
108 | GetRouterOutlet.pickPages({ | 108 | GetRouterOutlet.pickPages({ |
109 | Widget Function(GetDelegate delegate)? emptyWidget, | 109 | Widget Function(GetDelegate delegate)? emptyWidget, |
110 | GetPage Function(GetDelegate delegate)? emptyPage, | 110 | GetPage Function(GetDelegate delegate)? emptyPage, |
111 | - required Iterable<GetPage> Function(GetNavConfig currentNavStack) pickPages, | 111 | + required Iterable<GetPage> Function(RouteDecoder currentNavStack) pickPages, |
112 | bool Function(Route<dynamic>, dynamic)? onPopPage, | 112 | bool Function(Route<dynamic>, dynamic)? onPopPage, |
113 | GlobalKey<NavigatorState>? key, | 113 | GlobalKey<NavigatorState>? key, |
114 | GetDelegate? delegate, | 114 | GetDelegate? delegate, |
@@ -137,14 +137,14 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { | @@ -137,14 +137,14 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> { | ||
137 | return (emptyWidget?.call(rDelegate) ?? SizedBox.shrink()); | 137 | return (emptyWidget?.call(rDelegate) ?? SizedBox.shrink()); |
138 | }, | 138 | }, |
139 | pickPages: pickPages, | 139 | pickPages: pickPages, |
140 | - delegate: delegate ?? Get.rootDelegate, | 140 | + delegate: delegate ?? GetMaterialController.to.rootDelegate, |
141 | ); | 141 | ); |
142 | 142 | ||
143 | GetRouterOutlet.builder({ | 143 | GetRouterOutlet.builder({ |
144 | required Widget Function( | 144 | required Widget Function( |
145 | BuildContext context, | 145 | BuildContext context, |
146 | GetDelegate delegate, | 146 | GetDelegate delegate, |
147 | - GetNavConfig? currentRoute, | 147 | + RouteDecoder? currentRoute, |
148 | ) | 148 | ) |
149 | builder, | 149 | builder, |
150 | GetDelegate? routerDelegate, | 150 | GetDelegate? routerDelegate, |
@@ -154,16 +154,18 @@ extension ListExtension<E> on List<E> { | @@ -154,16 +154,18 @@ extension ListExtension<E> on List<E> { | ||
154 | // (this as RxList)._value; | 154 | // (this as RxList)._value; |
155 | // } | 155 | // } |
156 | 156 | ||
157 | - clear(); | 157 | + if (this is RxList) { |
158 | + (this as RxList).value.clear(); | ||
159 | + } | ||
158 | add(item); | 160 | add(item); |
159 | } | 161 | } |
160 | 162 | ||
161 | /// Replaces all existing items of this list with [items] | 163 | /// Replaces all existing items of this list with [items] |
162 | void assignAll(Iterable<E> items) { | 164 | void assignAll(Iterable<E> items) { |
163 | - // if (this is RxList) { | ||
164 | - // (this as RxList)._value; | ||
165 | - // } | ||
166 | - clear(); | 165 | + if (this is RxList) { |
166 | + (this as RxList).value.clear(); | ||
167 | + } | ||
168 | + //clear(); | ||
167 | addAll(items); | 169 | addAll(items); |
168 | } | 170 | } |
169 | } | 171 | } |
@@ -26,25 +26,25 @@ extension _Empty on Object { | @@ -26,25 +26,25 @@ extension _Empty on Object { | ||
26 | 26 | ||
27 | mixin StateMixin<T> on ListNotifier { | 27 | mixin StateMixin<T> on ListNotifier { |
28 | late T _value; | 28 | late T _value; |
29 | - GetState<T>? _status; | 29 | + GetStatus<T>? _status; |
30 | 30 | ||
31 | void _fillInitialStatus() { | 31 | void _fillInitialStatus() { |
32 | _status = (value == null || value!._isEmpty()) | 32 | _status = (value == null || value!._isEmpty()) |
33 | - ? GetState<T>.loading() | ||
34 | - : GetState<T>.success(_value); | 33 | + ? GetStatus<T>.loading() |
34 | + : GetStatus<T>.success(_value); | ||
35 | } | 35 | } |
36 | 36 | ||
37 | - GetState<T> get status { | 37 | + GetStatus<T> get status { |
38 | reportRead(); | 38 | reportRead(); |
39 | - return _status ??= _status = GetState.loading(); | 39 | + return _status ??= _status = GetStatus.loading(); |
40 | } | 40 | } |
41 | 41 | ||
42 | T get state => value; | 42 | T get state => value; |
43 | 43 | ||
44 | - set status(GetState<T> newStatus) { | 44 | + set status(GetStatus<T> newStatus) { |
45 | if (newStatus == status) return; | 45 | if (newStatus == status) return; |
46 | _status = newStatus; | 46 | _status = newStatus; |
47 | - if (newStatus is SuccessState<T>) { | 47 | + if (newStatus is SuccessStatus<T>) { |
48 | _value = newStatus.data!; | 48 | _value = newStatus.data!; |
49 | return; | 49 | return; |
50 | } | 50 | } |
@@ -69,12 +69,15 @@ mixin StateMixin<T> on ListNotifier { | @@ -69,12 +69,15 @@ mixin StateMixin<T> on ListNotifier { | ||
69 | final compute = body(); | 69 | final compute = body(); |
70 | compute().then((newValue) { | 70 | compute().then((newValue) { |
71 | if ((newValue == null || newValue._isEmpty()) && useEmpty) { | 71 | if ((newValue == null || newValue._isEmpty()) && useEmpty) { |
72 | - status = GetState<T>.loading(); | 72 | + status = GetStatus<T>.loading(); |
73 | } else { | 73 | } else { |
74 | - status = GetState<T>.success(newValue); | 74 | + status = GetStatus<T>.success(newValue); |
75 | } | 75 | } |
76 | + | ||
77 | + refresh(); | ||
76 | }, onError: (err) { | 78 | }, onError: (err) { |
77 | - status = GetState.error(errorMessage ?? err.toString()); | 79 | + status = GetStatus.error(errorMessage ?? err.toString()); |
80 | + refresh(); | ||
78 | }); | 81 | }); |
79 | } | 82 | } |
80 | } | 83 | } |
@@ -88,6 +91,8 @@ class GetListenable<T> extends ListNotifierSingle implements RxInterface<T> { | @@ -88,6 +91,8 @@ class GetListenable<T> extends ListNotifierSingle implements RxInterface<T> { | ||
88 | if (_controller == null) { | 91 | if (_controller == null) { |
89 | _controller = StreamController<T>.broadcast(); | 92 | _controller = StreamController<T>.broadcast(); |
90 | addListener(_streamListener); | 93 | addListener(_streamListener); |
94 | + | ||
95 | + ///TODO: report to controller dispose | ||
91 | } | 96 | } |
92 | return _controller!; | 97 | return _controller!; |
93 | } | 98 | } |
@@ -228,39 +233,39 @@ extension StateExt<T> on StateMixin<T> { | @@ -228,39 +233,39 @@ extension StateExt<T> on StateMixin<T> { | ||
228 | 233 | ||
229 | typedef NotifierBuilder<T> = Widget Function(T state); | 234 | typedef NotifierBuilder<T> = Widget Function(T state); |
230 | 235 | ||
231 | -abstract class GetState<T> { | ||
232 | - const GetState(); | ||
233 | - factory GetState.loading() => LoadingState(); | ||
234 | - factory GetState.error(String message) => ErrorState(message); | ||
235 | - factory GetState.empty() => EmptyState(); | ||
236 | - factory GetState.success(T data) => SuccessState(data); | 236 | +abstract class GetStatus<T> { |
237 | + const GetStatus(); | ||
238 | + factory GetStatus.loading() => LoadingStatus(); | ||
239 | + factory GetStatus.error(String message) => ErrorStatus(message); | ||
240 | + factory GetStatus.empty() => EmptyStatus(); | ||
241 | + factory GetStatus.success(T data) => SuccessStatus(data); | ||
237 | } | 242 | } |
238 | 243 | ||
239 | -class LoadingState<T> extends GetState<T> {} | 244 | +class LoadingStatus<T> extends GetStatus<T> {} |
240 | 245 | ||
241 | -class SuccessState<T> extends GetState<T> { | 246 | +class SuccessStatus<T> extends GetStatus<T> { |
242 | final T data; | 247 | final T data; |
243 | 248 | ||
244 | - SuccessState(this.data); | 249 | + SuccessStatus(this.data); |
245 | } | 250 | } |
246 | 251 | ||
247 | -class ErrorState<T, S> extends GetState<T> { | 252 | +class ErrorStatus<T, S> extends GetStatus<T> { |
248 | final S? error; | 253 | final S? error; |
249 | - ErrorState([this.error]); | 254 | + ErrorStatus([this.error]); |
250 | } | 255 | } |
251 | 256 | ||
252 | -class EmptyState<T> extends GetState<T> {} | 257 | +class EmptyStatus<T> extends GetStatus<T> {} |
253 | 258 | ||
254 | -extension StatusDataExt<T> on GetState<T> { | ||
255 | - bool get isLoading => this is LoadingState; | ||
256 | - bool get isSuccess => this is SuccessState; | ||
257 | - bool get isError => this is ErrorState; | ||
258 | - bool get isEmpty => this is EmptyState; | 259 | +extension StatusDataExt<T> on GetStatus<T> { |
260 | + bool get isLoading => this is LoadingStatus; | ||
261 | + bool get isSuccess => this is SuccessStatus; | ||
262 | + bool get isError => this is ErrorStatus; | ||
263 | + bool get isEmpty => this is EmptyStatus; | ||
259 | bool get isCustom => !isLoading && !isSuccess && !isError && !isEmpty; | 264 | bool get isCustom => !isLoading && !isSuccess && !isError && !isEmpty; |
260 | String get errorMessage { | 265 | String get errorMessage { |
261 | - final isError = this is ErrorState; | 266 | + final isError = this is ErrorStatus; |
262 | if (isError) { | 267 | if (isError) { |
263 | - final err = this as ErrorState; | 268 | + final err = this as ErrorStatus; |
264 | if (err.error != null && err.error is String) { | 269 | if (err.error != null && err.error is String) { |
265 | return err.error as String; | 270 | return err.error as String; |
266 | } | 271 | } |
@@ -270,8 +275,8 @@ extension StatusDataExt<T> on GetState<T> { | @@ -270,8 +275,8 @@ extension StatusDataExt<T> on GetState<T> { | ||
270 | } | 275 | } |
271 | 276 | ||
272 | T? get data { | 277 | T? get data { |
273 | - if (this is SuccessState<T>) { | ||
274 | - final success = this as SuccessState<T>; | 278 | + if (this is SuccessStatus<T>) { |
279 | + final success = this as SuccessStatus<T>; | ||
275 | return success.data; | 280 | return success.data; |
276 | } | 281 | } |
277 | return null; | 282 | return null; |
@@ -10,13 +10,13 @@ typedef GetControllerBuilder<T extends GetLifeCycleMixin> = Widget Function( | @@ -10,13 +10,13 @@ typedef GetControllerBuilder<T extends GetLifeCycleMixin> = Widget Function( | ||
10 | T controller); | 10 | T controller); |
11 | 11 | ||
12 | extension WatchExt on BuildContext { | 12 | extension WatchExt on BuildContext { |
13 | - T listen<T extends GetxController>() { | 13 | + T listen<T>() { |
14 | return Bind.of(this, rebuild: true); | 14 | return Bind.of(this, rebuild: true); |
15 | } | 15 | } |
16 | } | 16 | } |
17 | 17 | ||
18 | extension ReadExt on BuildContext { | 18 | extension ReadExt on BuildContext { |
19 | - T get<T extends GetxController>() { | 19 | + T get<T>() { |
20 | return Bind.of(this); | 20 | return Bind.of(this); |
21 | } | 21 | } |
22 | } | 22 | } |
@@ -212,7 +212,7 @@ abstract class Bind<T> extends StatelessWidget { | @@ -212,7 +212,7 @@ abstract class Bind<T> extends StatelessWidget { | ||
212 | child: child, | 212 | child: child, |
213 | ); | 213 | ); |
214 | 214 | ||
215 | - static T of<T extends GetxController>( | 215 | + static T of<T>( |
216 | BuildContext context, { | 216 | BuildContext context, { |
217 | bool rebuild = false, | 217 | bool rebuild = false, |
218 | // Object Function(T value)? filter, | 218 | // Object Function(T value)? filter, |
@@ -21,7 +21,7 @@ class ListNotifierGroup = ListNotifier with ListNotifierGroupMixin; | @@ -21,7 +21,7 @@ class ListNotifierGroup = ListNotifier with ListNotifierGroupMixin; | ||
21 | /// This mixin add to Listenable the addListener, removerListener and | 21 | /// This mixin add to Listenable the addListener, removerListener and |
22 | /// containsListener implementation | 22 | /// containsListener implementation |
23 | mixin ListNotifierSingleMixin on Listenable { | 23 | mixin ListNotifierSingleMixin on Listenable { |
24 | - List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[]; | 24 | + List<GetStateUpdate>? _updaters = <GetStateUpdate>[]; |
25 | 25 | ||
26 | @override | 26 | @override |
27 | Disposer addListener(GetStateUpdate listener) { | 27 | Disposer addListener(GetStateUpdate listener) { |
@@ -57,8 +57,9 @@ mixin ListNotifierSingleMixin on Listenable { | @@ -57,8 +57,9 @@ mixin ListNotifierSingleMixin on Listenable { | ||
57 | } | 57 | } |
58 | 58 | ||
59 | void _notifyUpdate() { | 59 | void _notifyUpdate() { |
60 | - for (var element in _updaters!) { | ||
61 | - element!(); | 60 | + final list = _updaters?.toList() ?? []; |
61 | + for (var element in list) { | ||
62 | + element(); | ||
62 | } | 63 | } |
63 | } | 64 | } |
64 | 65 |
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | 2 | ||
3 | +import 'package:flutter/scheduler.dart'; | ||
3 | import 'package:flutter/widgets.dart'; | 4 | import 'package:flutter/widgets.dart'; |
4 | 5 | ||
5 | import 'list_notifier.dart'; | 6 | import 'list_notifier.dart'; |
@@ -95,8 +96,26 @@ mixin ObserverComponent on ComponentElement { | @@ -95,8 +96,26 @@ mixin ObserverComponent on ComponentElement { | ||
95 | 96 | ||
96 | void getUpdate() { | 97 | void getUpdate() { |
97 | if (disposers != null) { | 98 | if (disposers != null) { |
99 | + _safeRebuild(); | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | + Future<bool> _safeRebuild() async { | ||
104 | + if (dirty) return false; | ||
105 | + if (SchedulerBinding.instance == null) { | ||
98 | markNeedsBuild(); | 106 | markNeedsBuild(); |
107 | + } else { | ||
108 | + // refresh was called during the building | ||
109 | + if (SchedulerBinding.instance!.schedulerPhase != SchedulerPhase.idle) { | ||
110 | + // Await for the end of build | ||
111 | + await SchedulerBinding.instance!.endOfFrame; | ||
112 | + if (dirty) return false; | ||
99 | } | 113 | } |
114 | + | ||
115 | + markNeedsBuild(); | ||
116 | + } | ||
117 | + | ||
118 | + return true; | ||
100 | } | 119 | } |
101 | 120 | ||
102 | @override | 121 | @override |
1 | -import 'package:collection/collection.dart'; | ||
2 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
3 | 2 | ||
4 | extension ContextExt on BuildContext { | 3 | extension ContextExt on BuildContext { |
@@ -170,3 +169,12 @@ extension ContextExt on BuildContext { | @@ -170,3 +169,12 @@ extension ContextExt on BuildContext { | ||
170 | return strictValues.firstOrNull ?? looseValues.first; | 169 | return strictValues.firstOrNull ?? looseValues.first; |
171 | } | 170 | } |
172 | } | 171 | } |
172 | + | ||
173 | +extension IterableExt<T> on Iterable<T> { | ||
174 | + /// The first element, or `null` if the iterable is empty. | ||
175 | + T? get firstOrNull { | ||
176 | + var iterator = this.iterator; | ||
177 | + if (iterator.moveNext()) return iterator.current; | ||
178 | + return null; | ||
179 | + } | ||
180 | +} |
1 | name: get | 1 | name: get |
2 | description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX. | 2 | description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX. |
3 | -version: 4.6.1 | 3 | +version: 5.0.0-beta.14 |
4 | homepage: https://github.com/jonataslaw/getx | 4 | homepage: https://github.com/jonataslaw/getx |
5 | 5 | ||
6 | environment: | 6 | environment: |
7 | - sdk: '>=2.12.0 <3.0.0' | 7 | + sdk: '>=2.13.0 <3.0.0' |
8 | 8 | ||
9 | dependencies: | 9 | dependencies: |
10 | flutter: | 10 | flutter: |
11 | sdk: flutter | 11 | sdk: flutter |
12 | + flutter_web_plugins: | ||
13 | + sdk: flutter | ||
12 | 14 | ||
13 | dev_dependencies: | 15 | dev_dependencies: |
14 | flutter_test: | 16 | flutter_test: |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | import 'package:flutter_test/flutter_test.dart'; | 2 | import 'package:flutter_test/flutter_test.dart'; |
3 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | + | ||
4 | import 'utils/wrapper.dart'; | 5 | import 'utils/wrapper.dart'; |
5 | 6 | ||
6 | void main() { | 7 | void main() { |
@@ -9,6 +10,8 @@ void main() { | @@ -9,6 +10,8 @@ void main() { | ||
9 | Wrapper(child: Container()), | 10 | Wrapper(child: Container()), |
10 | ); | 11 | ); |
11 | 12 | ||
13 | + await tester.pump(); | ||
14 | + | ||
12 | Get.bottomSheet(Container( | 15 | Get.bottomSheet(Container( |
13 | child: Wrap( | 16 | child: Wrap( |
14 | children: <Widget>[ | 17 | children: <Widget>[ |
@@ -31,6 +34,8 @@ void main() { | @@ -31,6 +34,8 @@ void main() { | ||
31 | Wrapper(child: Container()), | 34 | Wrapper(child: Container()), |
32 | ); | 35 | ); |
33 | 36 | ||
37 | + await tester.pump(); | ||
38 | + | ||
34 | Get.bottomSheet(Container( | 39 | Get.bottomSheet(Container( |
35 | child: Wrap( | 40 | child: Wrap( |
36 | children: <Widget>[ | 41 | children: <Widget>[ |
@@ -43,9 +48,13 @@ void main() { | @@ -43,9 +48,13 @@ void main() { | ||
43 | ), | 48 | ), |
44 | )); | 49 | )); |
45 | 50 | ||
51 | + await tester.pumpAndSettle(); | ||
52 | + | ||
46 | expect(Get.isBottomSheetOpen, true); | 53 | expect(Get.isBottomSheetOpen, true); |
47 | 54 | ||
48 | Get.back(); | 55 | Get.back(); |
56 | + await tester.pumpAndSettle(); | ||
57 | + | ||
49 | expect(Get.isBottomSheetOpen, false); | 58 | expect(Get.isBottomSheetOpen, false); |
50 | 59 | ||
51 | // expect(() => Get.bottomSheet(Container(), isScrollControlled: null), | 60 | // expect(() => Get.bottomSheet(Container(), isScrollControlled: null), |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | import 'package:flutter_test/flutter_test.dart'; | 2 | import 'package:flutter_test/flutter_test.dart'; |
3 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | + | ||
4 | import 'utils/wrapper.dart'; | 5 | import 'utils/wrapper.dart'; |
5 | 6 | ||
6 | void main() { | 7 | void main() { |
@@ -9,6 +10,8 @@ void main() { | @@ -9,6 +10,8 @@ void main() { | ||
9 | Wrapper(child: Container()), | 10 | Wrapper(child: Container()), |
10 | ); | 11 | ); |
11 | 12 | ||
13 | + await tester.pump(); | ||
14 | + | ||
12 | Get.defaultDialog( | 15 | Get.defaultDialog( |
13 | onConfirm: () => print("Ok"), | 16 | onConfirm: () => print("Ok"), |
14 | middleText: "Dialog made in 3 lines of code"); | 17 | middleText: "Dialog made in 3 lines of code"); |
@@ -23,6 +26,8 @@ void main() { | @@ -23,6 +26,8 @@ void main() { | ||
23 | Wrapper(child: Container()), | 26 | Wrapper(child: Container()), |
24 | ); | 27 | ); |
25 | 28 | ||
29 | + await tester.pump(); | ||
30 | + | ||
26 | Get.dialog(YourDialogWidget()); | 31 | Get.dialog(YourDialogWidget()); |
27 | 32 | ||
28 | await tester.pumpAndSettle(); | 33 | await tester.pumpAndSettle(); |
@@ -35,11 +40,20 @@ void main() { | @@ -35,11 +40,20 @@ void main() { | ||
35 | Wrapper(child: Container()), | 40 | Wrapper(child: Container()), |
36 | ); | 41 | ); |
37 | 42 | ||
43 | + await tester.pump(); | ||
44 | + | ||
38 | Get.dialog(YourDialogWidget()); | 45 | Get.dialog(YourDialogWidget()); |
39 | - expect(Get.isDialogOpen, true); | 46 | + await tester.pumpAndSettle(); |
47 | + | ||
48 | + expect(find.byType(YourDialogWidget), findsOneWidget); | ||
49 | + // expect(Get.isDialogOpen, true); | ||
50 | + | ||
40 | Get.back(); | 51 | Get.back(); |
41 | - expect(Get.isDialogOpen, false); | ||
42 | await tester.pumpAndSettle(); | 52 | await tester.pumpAndSettle(); |
53 | + | ||
54 | + expect(find.byType(YourDialogWidget), findsNothing); | ||
55 | + // expect(Get.isDialogOpen, false); | ||
56 | + // await tester.pumpAndSettle(); | ||
43 | }); | 57 | }); |
44 | } | 58 | } |
45 | 59 |
@@ -13,7 +13,7 @@ void main() { | @@ -13,7 +13,7 @@ void main() { | ||
13 | expect(Get.isRegistered<Controller2>(), false); | 13 | expect(Get.isRegistered<Controller2>(), false); |
14 | expect(Get.isRegistered<Controller>(), false); | 14 | expect(Get.isRegistered<Controller>(), false); |
15 | 15 | ||
16 | - Get.to(First()); | 16 | + Get.to(() => First()); |
17 | 17 | ||
18 | await tester.pumpAndSettle(); | 18 | await tester.pumpAndSettle(); |
19 | 19 | ||
@@ -21,7 +21,7 @@ void main() { | @@ -21,7 +21,7 @@ void main() { | ||
21 | 21 | ||
22 | expect(Get.isRegistered<Controller>(), true); | 22 | expect(Get.isRegistered<Controller>(), true); |
23 | 23 | ||
24 | - Get.to(Second()); | 24 | + Get.to(() => Second()); |
25 | 25 | ||
26 | await tester.pumpAndSettle(); | 26 | await tester.pumpAndSettle(); |
27 | 27 |
@@ -8,7 +8,7 @@ void main() { | @@ -8,7 +8,7 @@ void main() { | ||
8 | testWidgets("Get.to navigates to provided route", (tester) async { | 8 | testWidgets("Get.to navigates to provided route", (tester) async { |
9 | await tester.pumpWidget(Wrapper(child: Container())); | 9 | await tester.pumpWidget(Wrapper(child: Container())); |
10 | 10 | ||
11 | - Get.to(FirstScreen()); | 11 | + Get.to(() => FirstScreen()); |
12 | 12 | ||
13 | await tester.pumpAndSettle(); | 13 | await tester.pumpAndSettle(); |
14 | 14 | ||
@@ -47,13 +47,16 @@ void main() { | @@ -47,13 +47,16 @@ void main() { | ||
47 | 47 | ||
48 | await tester.pumpAndSettle(); | 48 | await tester.pumpAndSettle(); |
49 | 49 | ||
50 | - expect(Get.currentRoute, '/404'); | 50 | + expect( |
51 | + GetMaterialController.to.rootDelegate.currentConfiguration?.route?.name, | ||
52 | + '/404'); | ||
51 | }); | 53 | }); |
52 | 54 | ||
53 | testWidgets("Get.off navigates to provided route", (tester) async { | 55 | testWidgets("Get.off navigates to provided route", (tester) async { |
54 | await tester.pumpWidget(Wrapper(child: FirstScreen())); | 56 | await tester.pumpWidget(Wrapper(child: FirstScreen())); |
57 | + // await tester.pump(); | ||
55 | 58 | ||
56 | - Get.off(SecondScreen()); | 59 | + Get.off(() => SecondScreen()); |
57 | 60 | ||
58 | await tester.pumpAndSettle(); | 61 | await tester.pumpAndSettle(); |
59 | 62 | ||
@@ -62,8 +65,9 @@ void main() { | @@ -62,8 +65,9 @@ void main() { | ||
62 | 65 | ||
63 | testWidgets("Get.off removes current route", (tester) async { | 66 | testWidgets("Get.off removes current route", (tester) async { |
64 | await tester.pumpWidget(Wrapper(child: FirstScreen())); | 67 | await tester.pumpWidget(Wrapper(child: FirstScreen())); |
68 | + await tester.pump(); | ||
65 | 69 | ||
66 | - Get.off(SecondScreen()); | 70 | + Get.off(() => SecondScreen()); |
67 | Get.back(); | 71 | Get.back(); |
68 | 72 | ||
69 | await tester.pumpAndSettle(); | 73 | await tester.pumpAndSettle(); |
@@ -81,6 +85,8 @@ void main() { | @@ -81,6 +85,8 @@ void main() { | ||
81 | ], | 85 | ], |
82 | )); | 86 | )); |
83 | 87 | ||
88 | + await tester.pump(); | ||
89 | + | ||
84 | Get.offNamed('/second'); | 90 | Get.offNamed('/second'); |
85 | 91 | ||
86 | await tester.pumpAndSettle(); | 92 | await tester.pumpAndSettle(); |
@@ -98,7 +104,10 @@ void main() { | @@ -98,7 +104,10 @@ void main() { | ||
98 | ], | 104 | ], |
99 | )); | 105 | )); |
100 | 106 | ||
107 | + await tester.pump(); | ||
108 | + | ||
101 | Get.offNamed('/second'); | 109 | Get.offNamed('/second'); |
110 | + await tester.pumpAndSettle(); | ||
102 | Get.back(); | 111 | Get.back(); |
103 | 112 | ||
104 | await tester.pumpAndSettle(); | 113 | await tester.pumpAndSettle(); |
@@ -116,19 +125,24 @@ void main() { | @@ -116,19 +125,24 @@ void main() { | ||
116 | ], | 125 | ], |
117 | )); | 126 | )); |
118 | 127 | ||
128 | + // await tester.pump(); | ||
129 | + | ||
119 | Get.toNamed('/second'); | 130 | Get.toNamed('/second'); |
131 | + await tester.pumpAndSettle(); | ||
120 | Get.offNamed('/third'); | 132 | Get.offNamed('/third'); |
133 | + await tester.pumpAndSettle(); | ||
121 | Get.back(); | 134 | Get.back(); |
122 | - | ||
123 | await tester.pumpAndSettle(); | 135 | await tester.pumpAndSettle(); |
124 | 136 | ||
125 | expect(find.byType(FirstScreen), findsOneWidget); | 137 | expect(find.byType(FirstScreen), findsOneWidget); |
138 | + await tester.pumpAndSettle(); | ||
126 | }); | 139 | }); |
127 | 140 | ||
128 | testWidgets("Get.offAll navigates to provided route", (tester) async { | 141 | testWidgets("Get.offAll navigates to provided route", (tester) async { |
129 | await tester.pumpWidget(Wrapper(child: FirstScreen())); | 142 | await tester.pumpWidget(Wrapper(child: FirstScreen())); |
143 | + await tester.pump(); | ||
130 | 144 | ||
131 | - Get.offAll(SecondScreen()); | 145 | + Get.offAll(() => SecondScreen()); |
132 | 146 | ||
133 | await tester.pumpAndSettle(); | 147 | await tester.pumpAndSettle(); |
134 | 148 | ||
@@ -137,11 +151,13 @@ void main() { | @@ -137,11 +151,13 @@ void main() { | ||
137 | 151 | ||
138 | testWidgets("Get.offAll removes all previous routes", (tester) async { | 152 | testWidgets("Get.offAll removes all previous routes", (tester) async { |
139 | await tester.pumpWidget(Wrapper(child: FirstScreen())); | 153 | await tester.pumpWidget(Wrapper(child: FirstScreen())); |
154 | + await tester.pump(); | ||
140 | 155 | ||
141 | - Get.to(SecondScreen()); | ||
142 | - Get.offAll(ThirdScreen()); | 156 | + Get.to(() => SecondScreen()); |
157 | + await tester.pumpAndSettle(); | ||
158 | + Get.offAll(() => ThirdScreen()); | ||
159 | + await tester.pumpAndSettle(); | ||
143 | Get.back(); | 160 | Get.back(); |
144 | - | ||
145 | await tester.pumpAndSettle(); | 161 | await tester.pumpAndSettle(); |
146 | 162 | ||
147 | expect(find.byType(SecondScreen), findsNothing); | 163 | expect(find.byType(SecondScreen), findsNothing); |
@@ -164,6 +180,8 @@ void main() { | @@ -164,6 +180,8 @@ void main() { | ||
164 | ], | 180 | ], |
165 | )); | 181 | )); |
166 | 182 | ||
183 | + await tester.pump(); | ||
184 | + | ||
167 | Get.toNamed('/second'); | 185 | Get.toNamed('/second'); |
168 | 186 | ||
169 | await tester.pumpAndSettle(); | 187 | await tester.pumpAndSettle(); |
@@ -181,10 +199,13 @@ void main() { | @@ -181,10 +199,13 @@ void main() { | ||
181 | ], | 199 | ], |
182 | )); | 200 | )); |
183 | 201 | ||
202 | + await tester.pump(); | ||
203 | + | ||
184 | Get.toNamed('/second'); | 204 | Get.toNamed('/second'); |
205 | + await tester.pumpAndSettle(); | ||
185 | Get.offAllNamed('/third'); | 206 | Get.offAllNamed('/third'); |
207 | + await tester.pumpAndSettle(); | ||
186 | Get.back(); | 208 | Get.back(); |
187 | - | ||
188 | await tester.pumpAndSettle(); | 209 | await tester.pumpAndSettle(); |
189 | 210 | ||
190 | expect(find.byType(SecondScreen), findsNothing); | 211 | expect(find.byType(SecondScreen), findsNothing); |
@@ -224,6 +245,8 @@ void main() { | @@ -224,6 +245,8 @@ void main() { | ||
224 | )); | 245 | )); |
225 | 246 | ||
226 | Get.offAndToNamed('/second'); | 247 | Get.offAndToNamed('/second'); |
248 | + | ||
249 | + await tester.pumpAndSettle(); | ||
227 | Get.back(); | 250 | Get.back(); |
228 | 251 | ||
229 | await tester.pumpAndSettle(); | 252 | await tester.pumpAndSettle(); |
@@ -234,10 +257,11 @@ void main() { | @@ -234,10 +257,11 @@ void main() { | ||
234 | testWidgets("Get.offUntil navigates to provided route", (tester) async { | 257 | testWidgets("Get.offUntil navigates to provided route", (tester) async { |
235 | await tester.pumpWidget(Wrapper(child: Container())); | 258 | await tester.pumpWidget(Wrapper(child: Container())); |
236 | 259 | ||
237 | - Get.to(FirstScreen()); | 260 | + Get.to(() => FirstScreen()); |
238 | 261 | ||
239 | - Get.offUntil(GetPageRoute(page: () => ThirdScreen()), | ||
240 | - (route) => (route as GetPageRoute).routeName == '/FirstScreen'); | 262 | + await tester.pumpAndSettle(); |
263 | + | ||
264 | + Get.offUntil(() => ThirdScreen(), (route) => route.name == '/FirstScreen'); | ||
241 | 265 | ||
242 | await tester.pumpAndSettle(); | 266 | await tester.pumpAndSettle(); |
243 | 267 | ||
@@ -249,10 +273,12 @@ void main() { | @@ -249,10 +273,12 @@ void main() { | ||
249 | (tester) async { | 273 | (tester) async { |
250 | await tester.pumpWidget(Wrapper(child: Container())); | 274 | await tester.pumpWidget(Wrapper(child: Container())); |
251 | 275 | ||
252 | - Get.to(FirstScreen()); | ||
253 | - Get.to(SecondScreen()); | ||
254 | - Get.offUntil(GetPageRoute(page: () => ThirdScreen()), | ||
255 | - (route) => (route as GetPageRoute).routeName == '/FirstScreen'); | 276 | + Get.to(() => FirstScreen()); |
277 | + await tester.pumpAndSettle(); | ||
278 | + Get.to(() => SecondScreen()); | ||
279 | + await tester.pumpAndSettle(); | ||
280 | + Get.offUntil(() => ThirdScreen(), (route) => route.name == '/FirstScreen'); | ||
281 | + await tester.pumpAndSettle(); | ||
256 | Get.back(); | 282 | Get.back(); |
257 | 283 | ||
258 | await tester.pumpAndSettle(); | 284 | await tester.pumpAndSettle(); |
@@ -265,10 +291,12 @@ void main() { | @@ -265,10 +291,12 @@ void main() { | ||
265 | (tester) async { | 291 | (tester) async { |
266 | await tester.pumpWidget(Wrapper(child: Container())); | 292 | await tester.pumpWidget(Wrapper(child: Container())); |
267 | 293 | ||
268 | - Get.to(FirstScreen()); | ||
269 | - Get.to(SecondScreen()); | ||
270 | - Get.offUntil(GetPageRoute(page: () => ThirdScreen()), | ||
271 | - (route) => (route as GetPageRoute).routeName == '/FirstScreen'); | 294 | + Get.to(() => FirstScreen()); |
295 | + await tester.pumpAndSettle(); | ||
296 | + Get.to(() => SecondScreen()); | ||
297 | + await tester.pumpAndSettle(); | ||
298 | + Get.offUntil(() => ThirdScreen(), (route) => route.name == '/FirstScreen'); | ||
299 | + await tester.pumpAndSettle(); | ||
272 | Get.back(); | 300 | Get.back(); |
273 | 301 | ||
274 | await tester.pumpAndSettle(); | 302 | await tester.pumpAndSettle(); |
@@ -286,7 +314,7 @@ void main() { | @@ -286,7 +314,7 @@ void main() { | ||
286 | ], | 314 | ], |
287 | )); | 315 | )); |
288 | 316 | ||
289 | - Get.offNamedUntil('/second', ModalRoute.withName('/first')); | 317 | + Get.offNamedUntil('/second', (route) => route.name == '/first'); |
290 | 318 | ||
291 | await tester.pumpAndSettle(); | 319 | await tester.pumpAndSettle(); |
292 | 320 | ||
@@ -306,43 +334,52 @@ void main() { | @@ -306,43 +334,52 @@ void main() { | ||
306 | )); | 334 | )); |
307 | 335 | ||
308 | Get.toNamed('/second'); | 336 | Get.toNamed('/second'); |
309 | - Get.offNamedUntil('/third', ModalRoute.withName('/first')); | 337 | + await tester.pumpAndSettle(); |
338 | + Get.offNamedUntil('/third', (route) => route.name == '/first'); | ||
310 | 339 | ||
311 | await tester.pumpAndSettle(); | 340 | await tester.pumpAndSettle(); |
312 | 341 | ||
313 | expect(find.byType(SecondScreen), findsNothing); | 342 | expect(find.byType(SecondScreen), findsNothing); |
314 | }); | 343 | }); |
315 | 344 | ||
316 | - testWidgets( | ||
317 | - "Get.offNamedUntil leaves previous routes that match provided predicate", | ||
318 | - (tester) async { | ||
319 | - await tester.pumpWidget(WrapperNamed( | ||
320 | - initialRoute: '/first', | ||
321 | - namedRoutes: [ | ||
322 | - GetPage(page: () => FirstScreen(), name: '/first'), | ||
323 | - GetPage(page: () => SecondScreen(), name: '/second'), | ||
324 | - GetPage(page: () => ThirdScreen(), name: '/third'), | ||
325 | - ], | ||
326 | - )); | ||
327 | - | ||
328 | - Get.toNamed('/second'); | ||
329 | - Get.offNamedUntil('/third', ModalRoute.withName('/first')); | ||
330 | - Get.back(); | ||
331 | - | ||
332 | - await tester.pumpAndSettle(); | ||
333 | - | ||
334 | - expect(find.byType(FirstScreen), findsOneWidget); | ||
335 | - }); | 345 | + // testWidgets( |
346 | + // "Get.offNamedUntil leaves previous routes that match provided predicate", | ||
347 | + // (tester) async { | ||
348 | + // await tester.pumpWidget(WrapperNamed( | ||
349 | + // initialRoute: '/first', | ||
350 | + // namedRoutes: [ | ||
351 | + // GetPage(page: () => FirstScreen(), name: '/first'), | ||
352 | + // GetPage(page: () => SecondScreen(), name: '/second'), | ||
353 | + // GetPage(page: () => ThirdScreen(), name: '/third'), | ||
354 | + // ], | ||
355 | + // )); | ||
356 | + | ||
357 | + // Get.toNamed('/second'); | ||
358 | + // await tester.pumpAndSettle(); | ||
359 | + // Get.offNamedUntil('/third', (route) => route.name == '/first'); | ||
360 | + // await tester.pumpAndSettle(); | ||
361 | + // Get.back(); | ||
362 | + | ||
363 | + // await tester.pumpAndSettle(); | ||
364 | + | ||
365 | + // expect(find.byType(FirstScreen), findsOneWidget); | ||
366 | + // }); | ||
336 | 367 | ||
337 | testWidgets("Get.back navigates back", (tester) async { | 368 | testWidgets("Get.back navigates back", (tester) async { |
338 | await tester.pumpWidget( | 369 | await tester.pumpWidget( |
339 | Wrapper( | 370 | Wrapper( |
340 | - child: FirstScreen(), | 371 | + child: Container(), |
341 | defaultTransition: Transition.circularReveal, | 372 | defaultTransition: Transition.circularReveal, |
342 | ), | 373 | ), |
343 | ); | 374 | ); |
344 | 375 | ||
345 | - Get.to(SecondScreen()); | 376 | + // await tester.pump(); |
377 | + | ||
378 | + Get.to(() => FirstScreen()); | ||
379 | + await tester.pumpAndSettle(); | ||
380 | + | ||
381 | + Get.to(() => SecondScreen()); | ||
382 | + await tester.pumpAndSettle(); | ||
346 | Get.back(); | 383 | Get.back(); |
347 | 384 | ||
348 | await tester.pumpAndSettle(); | 385 | await tester.pumpAndSettle(); |
@@ -353,19 +390,32 @@ void main() { | @@ -353,19 +390,32 @@ void main() { | ||
353 | testWidgets( | 390 | testWidgets( |
354 | "Get.back with closeOverlays pops both snackbar and current route", | 391 | "Get.back with closeOverlays pops both snackbar and current route", |
355 | (tester) async { | 392 | (tester) async { |
356 | - await tester.pumpWidget(Wrapper(child: FirstScreen())); | 393 | + await tester.pumpWidget( |
394 | + Wrapper( | ||
395 | + child: Container(), | ||
396 | + defaultTransition: Transition.circularReveal, | ||
397 | + ), | ||
398 | + ); | ||
357 | 399 | ||
358 | - Get.to(SecondScreen()); | 400 | + // await tester.pump(); |
401 | + | ||
402 | + Get.to(() => FirstScreen()); | ||
403 | + await tester.pumpAndSettle(); | ||
404 | + Get.to(() => SecondScreen()); | ||
405 | + await tester.pumpAndSettle(); | ||
359 | Get.snackbar('title', "message"); | 406 | Get.snackbar('title', "message"); |
407 | + await tester.pumpAndSettle(); | ||
360 | Get.back(closeOverlays: true); | 408 | Get.back(closeOverlays: true); |
361 | 409 | ||
362 | await tester.pumpAndSettle(); | 410 | await tester.pumpAndSettle(); |
363 | 411 | ||
364 | expect(Get.isSnackbarOpen, false); | 412 | expect(Get.isSnackbarOpen, false); |
413 | + | ||
365 | expect(find.byType(FirstScreen), findsOneWidget); | 414 | expect(find.byType(FirstScreen), findsOneWidget); |
366 | }); | 415 | }); |
367 | 416 | ||
368 | - testWidgets("Get.defaultTransition smoke test", (tester) async { | 417 | + group("Get.defaultTransition smoke test", () { |
418 | + testWidgets("fadeIn", (tester) async { | ||
369 | await tester.pumpWidget( | 419 | await tester.pumpWidget( |
370 | Wrapper( | 420 | Wrapper( |
371 | child: Container(), | 421 | child: Container(), |
@@ -373,12 +423,14 @@ void main() { | @@ -373,12 +423,14 @@ void main() { | ||
373 | ), | 423 | ), |
374 | ); | 424 | ); |
375 | 425 | ||
376 | - Get.to(FirstScreen()); | 426 | + Get.to(() => FirstScreen()); |
377 | 427 | ||
378 | await tester.pumpAndSettle(); | 428 | await tester.pumpAndSettle(); |
379 | 429 | ||
380 | expect(find.byType(FirstScreen), findsOneWidget); | 430 | expect(find.byType(FirstScreen), findsOneWidget); |
431 | + }); | ||
381 | 432 | ||
433 | + testWidgets("downToUp", (tester) async { | ||
382 | await tester.pumpWidget( | 434 | await tester.pumpWidget( |
383 | Wrapper( | 435 | Wrapper( |
384 | child: Container(), | 436 | child: Container(), |
@@ -386,12 +438,14 @@ void main() { | @@ -386,12 +438,14 @@ void main() { | ||
386 | ), | 438 | ), |
387 | ); | 439 | ); |
388 | 440 | ||
389 | - Get.to(FirstScreen()); | 441 | + Get.to(() => FirstScreen()); |
390 | 442 | ||
391 | await tester.pumpAndSettle(); | 443 | await tester.pumpAndSettle(); |
392 | 444 | ||
393 | expect(find.byType(FirstScreen), findsOneWidget); | 445 | expect(find.byType(FirstScreen), findsOneWidget); |
446 | + }); | ||
394 | 447 | ||
448 | + testWidgets("fade", (tester) async { | ||
395 | await tester.pumpWidget( | 449 | await tester.pumpWidget( |
396 | Wrapper( | 450 | Wrapper( |
397 | child: Container(), | 451 | child: Container(), |
@@ -399,12 +453,14 @@ void main() { | @@ -399,12 +453,14 @@ void main() { | ||
399 | ), | 453 | ), |
400 | ); | 454 | ); |
401 | 455 | ||
402 | - Get.to(FirstScreen()); | 456 | + Get.to(() => FirstScreen()); |
403 | 457 | ||
404 | await tester.pumpAndSettle(); | 458 | await tester.pumpAndSettle(); |
405 | 459 | ||
406 | expect(find.byType(FirstScreen), findsOneWidget); | 460 | expect(find.byType(FirstScreen), findsOneWidget); |
461 | + }); | ||
407 | 462 | ||
463 | + testWidgets("leftToRight", (tester) async { | ||
408 | await tester.pumpWidget( | 464 | await tester.pumpWidget( |
409 | Wrapper( | 465 | Wrapper( |
410 | child: Container(), | 466 | child: Container(), |
@@ -412,12 +468,14 @@ void main() { | @@ -412,12 +468,14 @@ void main() { | ||
412 | ), | 468 | ), |
413 | ); | 469 | ); |
414 | 470 | ||
415 | - Get.to(FirstScreen()); | 471 | + Get.to(() => FirstScreen()); |
416 | 472 | ||
417 | await tester.pumpAndSettle(); | 473 | await tester.pumpAndSettle(); |
418 | 474 | ||
419 | expect(find.byType(FirstScreen), findsOneWidget); | 475 | expect(find.byType(FirstScreen), findsOneWidget); |
476 | + }); | ||
420 | 477 | ||
478 | + testWidgets("leftToRightWithFade", (tester) async { | ||
421 | await tester.pumpWidget( | 479 | await tester.pumpWidget( |
422 | Wrapper( | 480 | Wrapper( |
423 | child: Container(), | 481 | child: Container(), |
@@ -425,12 +483,29 @@ void main() { | @@ -425,12 +483,29 @@ void main() { | ||
425 | ), | 483 | ), |
426 | ); | 484 | ); |
427 | 485 | ||
428 | - Get.to(FirstScreen()); | 486 | + Get.to(() => FirstScreen()); |
487 | + | ||
488 | + await tester.pumpAndSettle(); | ||
489 | + | ||
490 | + expect(find.byType(FirstScreen), findsOneWidget); | ||
491 | + }); | ||
492 | + | ||
493 | + testWidgets("leftToRightWithFade", (tester) async { | ||
494 | + await tester.pumpWidget( | ||
495 | + Wrapper( | ||
496 | + child: Container(), | ||
497 | + defaultTransition: Transition.rightToLeft, | ||
498 | + ), | ||
499 | + ); | ||
500 | + | ||
501 | + Get.to(() => FirstScreen()); | ||
429 | 502 | ||
430 | await tester.pumpAndSettle(); | 503 | await tester.pumpAndSettle(); |
431 | 504 | ||
432 | expect(find.byType(FirstScreen), findsOneWidget); | 505 | expect(find.byType(FirstScreen), findsOneWidget); |
506 | + }); | ||
433 | 507 | ||
508 | + testWidgets("defaultTransition", (tester) async { | ||
434 | await tester.pumpWidget( | 509 | await tester.pumpWidget( |
435 | Wrapper( | 510 | Wrapper( |
436 | child: Container(), | 511 | child: Container(), |
@@ -438,12 +513,14 @@ void main() { | @@ -438,12 +513,14 @@ void main() { | ||
438 | ), | 513 | ), |
439 | ); | 514 | ); |
440 | 515 | ||
441 | - Get.to(FirstScreen()); | 516 | + Get.to(() => FirstScreen()); |
442 | 517 | ||
443 | await tester.pumpAndSettle(); | 518 | await tester.pumpAndSettle(); |
444 | 519 | ||
445 | expect(find.byType(FirstScreen), findsOneWidget); | 520 | expect(find.byType(FirstScreen), findsOneWidget); |
521 | + }); | ||
446 | 522 | ||
523 | + testWidgets("rightToLeftWithFade", (tester) async { | ||
447 | await tester.pumpWidget( | 524 | await tester.pumpWidget( |
448 | Wrapper( | 525 | Wrapper( |
449 | child: Container(), | 526 | child: Container(), |
@@ -451,12 +528,14 @@ void main() { | @@ -451,12 +528,14 @@ void main() { | ||
451 | ), | 528 | ), |
452 | ); | 529 | ); |
453 | 530 | ||
454 | - Get.to(FirstScreen()); | 531 | + Get.to(() => FirstScreen()); |
455 | 532 | ||
456 | await tester.pumpAndSettle(); | 533 | await tester.pumpAndSettle(); |
457 | 534 | ||
458 | expect(find.byType(FirstScreen), findsOneWidget); | 535 | expect(find.byType(FirstScreen), findsOneWidget); |
536 | + }); | ||
459 | 537 | ||
538 | + testWidgets("cupertino", (tester) async { | ||
460 | await tester.pumpWidget( | 539 | await tester.pumpWidget( |
461 | Wrapper( | 540 | Wrapper( |
462 | child: Container(), | 541 | child: Container(), |
@@ -464,12 +543,14 @@ void main() { | @@ -464,12 +543,14 @@ void main() { | ||
464 | ), | 543 | ), |
465 | ); | 544 | ); |
466 | 545 | ||
467 | - Get.to(FirstScreen()); | 546 | + Get.to(() => FirstScreen()); |
468 | 547 | ||
469 | await tester.pumpAndSettle(); | 548 | await tester.pumpAndSettle(); |
470 | 549 | ||
471 | expect(find.byType(FirstScreen), findsOneWidget); | 550 | expect(find.byType(FirstScreen), findsOneWidget); |
551 | + }); | ||
472 | 552 | ||
553 | + testWidgets("size", (tester) async { | ||
473 | await tester.pumpWidget( | 554 | await tester.pumpWidget( |
474 | Wrapper( | 555 | Wrapper( |
475 | child: Container(), | 556 | child: Container(), |
@@ -477,12 +558,13 @@ void main() { | @@ -477,12 +558,13 @@ void main() { | ||
477 | ), | 558 | ), |
478 | ); | 559 | ); |
479 | 560 | ||
480 | - Get.to(FirstScreen()); | 561 | + Get.to(() => FirstScreen()); |
481 | 562 | ||
482 | await tester.pumpAndSettle(); | 563 | await tester.pumpAndSettle(); |
483 | 564 | ||
484 | expect(find.byType(FirstScreen), findsOneWidget); | 565 | expect(find.byType(FirstScreen), findsOneWidget); |
485 | }); | 566 | }); |
567 | + }); | ||
486 | } | 568 | } |
487 | 569 | ||
488 | class FirstScreen extends StatelessWidget { | 570 | class FirstScreen extends StatelessWidget { |
@@ -5,8 +5,15 @@ import 'package:get/get.dart'; | @@ -5,8 +5,15 @@ import 'package:get/get.dart'; | ||
5 | import 'get_main_test.dart'; | 5 | import 'get_main_test.dart'; |
6 | 6 | ||
7 | class RedirectMiddleware extends GetMiddleware { | 7 | class RedirectMiddleware extends GetMiddleware { |
8 | + // @override | ||
9 | + // RouteSettings redirect(String? route) { | ||
10 | + // return RouteSettings(name: '/second'); | ||
11 | + // } | ||
12 | + | ||
8 | @override | 13 | @override |
9 | - RouteSettings redirect(String? route) => RouteSettings(name: '/second'); | 14 | + Future<RouteDecoder?> redirectDelegate(RouteDecoder route) async { |
15 | + return RouteDecoder.fromRoute('/second'); | ||
16 | + } | ||
10 | } | 17 | } |
11 | 18 | ||
12 | void main() { | 19 | void main() { |
@@ -16,10 +23,9 @@ void main() { | @@ -16,10 +23,9 @@ void main() { | ||
16 | initialRoute: '/', | 23 | initialRoute: '/', |
17 | getPages: [ | 24 | getPages: [ |
18 | GetPage(name: '/', page: () => Container()), | 25 | GetPage(name: '/', page: () => Container()), |
19 | - GetPage( | ||
20 | - name: '/first', | ||
21 | - page: () => FirstScreen(), | ||
22 | - middlewares: [RedirectMiddleware()]), | 26 | + GetPage(name: '/first', page: () => FirstScreen(), middlewares: [ |
27 | + RedirectMiddleware(), | ||
28 | + ]), | ||
23 | GetPage(name: '/second', page: () => SecondScreen()), | 29 | GetPage(name: '/second', page: () => SecondScreen()), |
24 | GetPage(name: '/third', page: () => ThirdScreen()), | 30 | GetPage(name: '/third', page: () => ThirdScreen()), |
25 | ], | 31 | ], |
@@ -29,7 +35,7 @@ void main() { | @@ -29,7 +35,7 @@ void main() { | ||
29 | Get.toNamed('/first'); | 35 | Get.toNamed('/first'); |
30 | 36 | ||
31 | await tester.pumpAndSettle(); | 37 | await tester.pumpAndSettle(); |
32 | - print(Get.routing.current); | 38 | + print(Get.rootController.rootDelegate.currentConfiguration?.route?.name); |
33 | expect(find.byType(SecondScreen), findsOneWidget); | 39 | expect(find.byType(SecondScreen), findsOneWidget); |
34 | }); | 40 | }); |
35 | } | 41 | } |
1 | import 'package:flutter/cupertino.dart'; | 1 | import 'package:flutter/cupertino.dart'; |
2 | import 'package:flutter_test/flutter_test.dart'; | 2 | import 'package:flutter_test/flutter_test.dart'; |
3 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | -import 'package:get/get_navigation/src/root/parse_route.dart'; | ||
5 | 4 | ||
6 | void main() { | 5 | void main() { |
7 | test('Parse Page with children', () { | 6 | test('Parse Page with children', () { |
@@ -14,9 +14,12 @@ void main() { | @@ -14,9 +14,12 @@ void main() { | ||
14 | child: Center( | 14 | child: Center( |
15 | child: CupertinoButton( | 15 | child: CupertinoButton( |
16 | onPressed: () { | 16 | onPressed: () { |
17 | - Get.to(() => CupertinoPageScaffold( | 17 | + Get.to( |
18 | + () => CupertinoPageScaffold( | ||
18 | child: Center(child: Text('route')), | 19 | child: Center(child: Text('route')), |
19 | - )); | 20 | + ), |
21 | + preventDuplicateHandlingMode: | ||
22 | + PreventDuplicateHandlingMode.Recreate); | ||
20 | }, | 23 | }, |
21 | child: const Text('push'), | 24 | child: const Text('push'), |
22 | ), | 25 | ), |
@@ -25,6 +28,8 @@ void main() { | @@ -25,6 +28,8 @@ void main() { | ||
25 | ), | 28 | ), |
26 | ); | 29 | ); |
27 | 30 | ||
31 | + await tester.pumpAndSettle(); | ||
32 | + | ||
28 | // Check the basic iOS back-swipe dismiss transition. Dragging the pushed | 33 | // Check the basic iOS back-swipe dismiss transition. Dragging the pushed |
29 | // route halfway across the screen will trigger the iOS dismiss animation | 34 | // route halfway across the screen will trigger the iOS dismiss animation |
30 | 35 | ||
@@ -52,7 +57,7 @@ void main() { | @@ -52,7 +57,7 @@ void main() { | ||
52 | of: find.text('push'), | 57 | of: find.text('push'), |
53 | matching: find.byType(CupertinoPageScaffold))) | 58 | matching: find.byType(CupertinoPageScaffold))) |
54 | .dx, | 59 | .dx, |
55 | - 0, | 60 | + moreOrLessEquals(-(400 / 3), epsilon: 1), |
56 | ); | 61 | ); |
57 | await tester.pumpAndSettle(); | 62 | await tester.pumpAndSettle(); |
58 | expect(find.text('push'), findsOneWidget); | 63 | expect(find.text('push'), findsOneWidget); |
@@ -99,22 +104,5 @@ void main() { | @@ -99,22 +104,5 @@ void main() { | ||
99 | .dx, | 104 | .dx, |
100 | moreOrLessEquals(798, epsilon: 1), | 105 | moreOrLessEquals(798, epsilon: 1), |
101 | ); | 106 | ); |
102 | - | ||
103 | - // Use the navigator to push a route instead of tapping the 'push' button. | ||
104 | - // The topmost route (the one that's animating away), ignores input while | ||
105 | - // the pop is underway because route.navigator.userGestureInProgress. | ||
106 | - Get.to(() => const CupertinoPageScaffold( | ||
107 | - child: Center(child: Text('route')), | ||
108 | - )); | ||
109 | - | ||
110 | - await tester.pumpAndSettle(); | ||
111 | - expect(find.text('route'), findsOneWidget); | ||
112 | - expect(find.text('push'), findsNothing); | ||
113 | - expect( | ||
114 | - tester | ||
115 | - .state<NavigatorState>(find.byType(Navigator)) | ||
116 | - .userGestureInProgress, | ||
117 | - false, | ||
118 | - ); | ||
119 | }); | 107 | }); |
120 | } | 108 | } |
@@ -23,6 +23,8 @@ void main() { | @@ -23,6 +23,8 @@ void main() { | ||
23 | ), | 23 | ), |
24 | ); | 24 | ); |
25 | 25 | ||
26 | + await tester.pump(); | ||
27 | + | ||
26 | expect(Get.isSnackbarOpen, false); | 28 | expect(Get.isSnackbarOpen, false); |
27 | await tester.tap(find.text('Open Snackbar')); | 29 | await tester.tap(find.text('Open Snackbar')); |
28 | 30 | ||
@@ -57,8 +59,12 @@ void main() { | @@ -57,8 +59,12 @@ void main() { | ||
57 | ), | 59 | ), |
58 | ); | 60 | ); |
59 | 61 | ||
62 | + await tester.pump(); | ||
63 | + | ||
60 | expect(Get.isSnackbarOpen, false); | 64 | expect(Get.isSnackbarOpen, false); |
61 | - await tester.tap(find.text('Open Snackbar')); | 65 | + await tester.tap( |
66 | + find.text('Open Snackbar'), | ||
67 | + ); | ||
62 | 68 | ||
63 | expect(Get.isSnackbarOpen, true); | 69 | expect(Get.isSnackbarOpen, true); |
64 | await tester.pump(const Duration(seconds: 1)); | 70 | await tester.pump(const Duration(seconds: 1)); |
@@ -85,6 +91,8 @@ void main() { | @@ -85,6 +91,8 @@ void main() { | ||
85 | ), | 91 | ), |
86 | ); | 92 | ); |
87 | 93 | ||
94 | + await tester.pump(); | ||
95 | + | ||
88 | expect(Get.isSnackbarOpen, false); | 96 | expect(Get.isSnackbarOpen, false); |
89 | await tester.tap(find.text('Open Snackbar')); | 97 | await tester.tap(find.text('Open Snackbar')); |
90 | expect(Get.isSnackbarOpen, true); | 98 | expect(Get.isSnackbarOpen, true); |
@@ -96,6 +104,7 @@ void main() { | @@ -96,6 +104,7 @@ void main() { | ||
96 | expect(find.text('title'), findsNothing); | 104 | expect(find.text('title'), findsNothing); |
97 | expect(find.text('titleTwo'), findsOneWidget); | 105 | expect(find.text('titleTwo'), findsOneWidget); |
98 | Get.closeAllSnackbars(); | 106 | Get.closeAllSnackbars(); |
107 | + await tester.pumpAndSettle(); | ||
99 | }); | 108 | }); |
100 | 109 | ||
101 | testWidgets("test snackbar dismissible", (tester) async { | 110 | testWidgets("test snackbar dismissible", (tester) async { |
@@ -134,6 +143,8 @@ void main() { | @@ -134,6 +143,8 @@ void main() { | ||
134 | ), | 143 | ), |
135 | )); | 144 | )); |
136 | 145 | ||
146 | + await tester.pump(); | ||
147 | + | ||
137 | expect(Get.isSnackbarOpen, false); | 148 | expect(Get.isSnackbarOpen, false); |
138 | expect(find.text('bar1'), findsNothing); | 149 | expect(find.text('bar1'), findsNothing); |
139 | 150 | ||
@@ -218,6 +229,8 @@ void main() { | @@ -218,6 +229,8 @@ void main() { | ||
218 | 229 | ||
219 | await tester.pumpWidget(GetMaterialApp(home: Scaffold())); | 230 | await tester.pumpWidget(GetMaterialApp(home: Scaffold())); |
220 | 231 | ||
232 | + await tester.pump(); | ||
233 | + | ||
221 | expect(Get.isSnackbarOpen, false); | 234 | expect(Get.isSnackbarOpen, false); |
222 | expect(find.text('bar1'), findsNothing); | 235 | expect(find.text('bar1'), findsNothing); |
223 | 236 |
@@ -23,9 +23,11 @@ class Wrapper extends StatelessWidget { | @@ -23,9 +23,11 @@ class Wrapper extends StatelessWidget { | ||
23 | translations: WrapperTranslations(), | 23 | translations: WrapperTranslations(), |
24 | locale: WrapperTranslations.locale, | 24 | locale: WrapperTranslations.locale, |
25 | getPages: namedRoutes, | 25 | getPages: namedRoutes, |
26 | - home: Scaffold( | 26 | + home: namedRoutes == null |
27 | + ? Scaffold( | ||
27 | body: child, | 28 | body: child, |
28 | - ), | 29 | + ) |
30 | + : null, | ||
29 | ); | 31 | ); |
30 | } | 32 | } |
31 | } | 33 | } |
@@ -97,7 +97,7 @@ void main() { | @@ -97,7 +97,7 @@ void main() { | ||
97 | controller.close(); | 97 | controller.close(); |
98 | }); | 98 | }); |
99 | 99 | ||
100 | - test('Rx same value will not call the same listener when `call`', () async { | 100 | + test('Rx same value will not call the same listener when call', () async { |
101 | var reactiveInteger = RxInt(2); | 101 | var reactiveInteger = RxInt(2); |
102 | var timesCalled = 0; | 102 | var timesCalled = 0; |
103 | reactiveInteger.listen((newInt) { | 103 | reactiveInteger.listen((newInt) { |
@@ -114,7 +114,7 @@ void main() { | @@ -114,7 +114,7 @@ void main() { | ||
114 | expect(1, timesCalled); | 114 | expect(1, timesCalled); |
115 | }); | 115 | }); |
116 | 116 | ||
117 | - test('Rx different value will call the listener when `trigger`', () async { | 117 | + test('Rx different value will call the listener when trigger', () async { |
118 | var reactiveInteger = RxInt(0); | 118 | var reactiveInteger = RxInt(0); |
119 | var timesCalled = 0; | 119 | var timesCalled = 0; |
120 | reactiveInteger.listen((newInt) { | 120 | reactiveInteger.listen((newInt) { |
@@ -131,7 +131,7 @@ void main() { | @@ -131,7 +131,7 @@ void main() { | ||
131 | expect(3, timesCalled); | 131 | expect(3, timesCalled); |
132 | }); | 132 | }); |
133 | 133 | ||
134 | - test('Rx same value will call the listener when `trigger`', () async { | 134 | + test('Rx same value will call the listener when trigger', () async { |
135 | var reactiveInteger = RxInt(2); | 135 | var reactiveInteger = RxInt(2); |
136 | var timesCalled = 0; | 136 | var timesCalled = 0; |
137 | reactiveInteger.listen((newInt) { | 137 | reactiveInteger.listen((newInt) { |
@@ -7,6 +7,8 @@ import '../../navigation/utils/wrapper.dart'; | @@ -7,6 +7,8 @@ import '../../navigation/utils/wrapper.dart'; | ||
7 | void main() { | 7 | void main() { |
8 | testWidgets("Get.defaultDialog smoke test", (tester) async { | 8 | testWidgets("Get.defaultDialog smoke test", (tester) async { |
9 | await tester.pumpWidget(Wrapper(child: Container())); | 9 | await tester.pumpWidget(Wrapper(child: Container())); |
10 | + await tester.pump(); | ||
11 | + | ||
10 | final BuildContext context = tester.element(find.byType(Container)); | 12 | final BuildContext context = tester.element(find.byType(Container)); |
11 | 13 | ||
12 | var mediaQuery = MediaQuery.of(context); | 14 | var mediaQuery = MediaQuery.of(context); |
-
Please register or login to post a comment