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