From 54ac4d8c26b424f28c88cbc7385159f065953385 Mon Sep 17 00:00:00 2001 From: milad Date: Sun, 28 Jul 2024 16:34:02 +0300 Subject: [PATCH 01/13] wip refactoring page builder --- auto_route/example/lib/mobile/main.dart | 2 +- .../example/lib/mobile/router/router.dart | 2 +- .../example/lib/mobile/router/router.gr.dart | 222 ++++++------- .../lib/mobile/screens/settings_page.dart | 2 +- .../lib/web_demo/router/web_router.dart | 71 +++-- .../lib/web_demo/router/web_router.gr.dart | 243 +++++++-------- auto_route/example/lib/web_demo/web_main.dart | 11 +- auto_route/lib/auto_route.dart | 27 ++ auto_route/lib/src/matcher/route_match.dart | 2 + auto_route/lib/src/matcher/route_matcher.dart | 2 +- .../lib/src/route/auto_route_config.dart | 88 +++--- auto_route/lib/src/route/page_info.dart | 35 ++- auto_route/lib/src/route/route_data.dart | 5 + auto_route/lib/src/route/route_type.dart | 4 +- .../router/controller/root_stack_router.dart | 57 ++-- .../router/controller/routing_controller.dart | 28 +- .../lib/src/router/widgets/auto_router.dart | 34 +- .../src/router/widgets/auto_tabs_router.dart | 1 - auto_route/test/main_router.gr.dart | 293 ++++++++---------- auto_route/test/page_info_test.dart | 8 - .../lib/src/code_builder/library_builder.dart | 2 - .../src/code_builder/route_info_builder.dart | 150 +++++++-- .../code_builder/router_config_builder.dart | 218 ------------- 23 files changed, 682 insertions(+), 825 deletions(-) delete mode 100644 auto_route/test/page_info_test.dart delete mode 100644 auto_route_generator/lib/src/code_builder/router_config_builder.dart diff --git a/auto_route/example/lib/mobile/main.dart b/auto_route/example/lib/mobile/main.dart index 7d8a1233..d8f0a849 100644 --- a/auto_route/example/lib/mobile/main.dart +++ b/auto_route/example/lib/mobile/main.dart @@ -15,7 +15,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { final authService = AuthService(); - final _rootRouter = RootRouter(); + final _rootRouter = AppRouter(); @override Widget build(BuildContext context) { diff --git a/auto_route/example/lib/mobile/router/router.dart b/auto_route/example/lib/mobile/router/router.dart index 3ee49d0c..15c8dff5 100644 --- a/auto_route/example/lib/mobile/router/router.dart +++ b/auto_route/example/lib/mobile/router/router.dart @@ -4,7 +4,7 @@ import 'package:example/mobile/router/router.gr.dart'; import 'package:example/mobile/screens/profile/routes.dart'; @AutoRouterConfig(generateForDir: ['lib/mobile']) -class RootRouter extends $RootRouter { +class AppRouter extends RootStackRouter { @override final List routes = [ AutoRoute(page: WelcomeRoute.page, initial: true), diff --git a/auto_route/example/lib/mobile/router/router.gr.dart b/auto_route/example/lib/mobile/router/router.gr.dart index 4437ec73..0a38a50d 100644 --- a/auto_route/example/lib/mobile/router/router.gr.dart +++ b/auto_route/example/lib/mobile/router/router.gr.dart @@ -19,114 +19,6 @@ import 'package:example/mobile/screens/profile/profile_page.dart' as _i7; import 'package:example/mobile/screens/settings_page.dart' as _i8; import 'package:flutter/material.dart' as _i10; -abstract class $RootRouter extends _i9.RootStackRouter { - $RootRouter({super.navigatorKey}); - - @override - final Map pagesMap = { - BookDetailsRoute.name: (routeData) { - final pathParams = routeData.inheritedPathParams; - final args = routeData.argsAs( - orElse: () => BookDetailsRouteArgs( - id: pathParams.getInt( - 'id', - -3, - ))); - return _i9.AutoRoutePage( - routeData: routeData, - child: _i1.BookDetailsPage(id: args.id), - ); - }, - BookListRoute.name: (routeData) { - return _i9.AutoRoutePage( - routeData: routeData, - child: _i2.BookListScreen(), - ); - }, - BooksTab.name: (routeData) { - return _i9.AutoRoutePage( - routeData: routeData, - child: const _i3.BooksTabPage(), - ); - }, - HomeRoute.name: (routeData) { - return _i9.AutoRoutePage( - routeData: routeData, - child: const _i4.HomePage(), - ); - }, - LoginRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const LoginRouteArgs()); - return _i9.AutoRoutePage( - routeData: routeData, - child: _i5.LoginPage( - key: args.key, - onLoginResult: args.onLoginResult, - showBackButton: args.showBackButton, - ), - ); - }, - MyBooksRoute.name: (routeData) { - final queryParams = routeData.queryParams; - final args = routeData.argsAs( - orElse: () => MyBooksRouteArgs( - filter: queryParams.optString( - 'filter', - 'none', - ))); - return _i9.AutoRoutePage( - routeData: routeData, - child: _i6.MyBooksPage( - key: args.key, - filter: args.filter, - ), - ); - }, - ProfileRoute.name: (routeData) { - return _i9.AutoRoutePage( - routeData: routeData, - child: _i7.ProfilePage(), - ); - }, - ProfileTab.name: (routeData) { - return _i9.AutoRoutePage( - routeData: routeData, - child: const _i3.ProfileTabPage(), - ); - }, - SettingsTab.name: (routeData) { - final pathParams = routeData.inheritedPathParams; - final queryParams = routeData.queryParams; - final args = routeData.argsAs( - orElse: () => SettingsTabArgs( - tab: pathParams.getString( - 'tab', - 'none', - ), - query: queryParams.getString( - 'query', - 'none', - ), - )); - return _i9.AutoRoutePage( - routeData: routeData, - child: _i8.SettingsPage( - key: args.key, - tab: args.tab, - query: args.query, - ), - ); - }, - WelcomeRoute.name: (routeData) { - return _i9.AutoRoutePage( - routeData: routeData, - child: const _i4.WelcomeScreen(), - ); - }, - }; -} - /// generated route for /// [_i1.BookDetailsPage] class BookDetailsRoute extends _i9.PageRouteInfo { @@ -142,8 +34,19 @@ class BookDetailsRoute extends _i9.PageRouteInfo { static const String name = 'BookDetailsRoute'; - static const _i9.PageInfo page = - _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final args = data.argsAs( + orElse: () => BookDetailsRouteArgs( + id: pathParams.getInt( + 'id', + -3, + ))); + return _i1.BookDetailsPage(id: args.id); + }, + ); } class BookDetailsRouteArgs { @@ -168,7 +71,12 @@ class BookListRoute extends _i9.PageRouteInfo { static const String name = 'BookListRoute'; - static const _i9.PageInfo page = _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return _i2.BookListScreen(); + }, + ); } /// generated route for @@ -182,7 +90,12 @@ class BooksTab extends _i9.PageRouteInfo { static const String name = 'BooksTab'; - static const _i9.PageInfo page = _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i3.BooksTabPage(); + }, + ); } /// generated route for @@ -196,7 +109,12 @@ class HomeRoute extends _i9.PageRouteInfo { static const String name = 'HomeRoute'; - static const _i9.PageInfo page = _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i4.HomePage(); + }, + ); } /// generated route for @@ -219,8 +137,18 @@ class LoginRoute extends _i9.PageRouteInfo { static const String name = 'LoginRoute'; - static const _i9.PageInfo page = - _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + final args = + data.argsAs(orElse: () => const LoginRouteArgs()); + return _i5.LoginPage( + key: args.key, + onLoginResult: args.onLoginResult, + showBackButton: args.showBackButton, + ); + }, + ); } class LoginRouteArgs { @@ -261,8 +189,22 @@ class MyBooksRoute extends _i9.PageRouteInfo { static const String name = 'MyBooksRoute'; - static const _i9.PageInfo page = - _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + final queryParams = data.queryParams; + final args = data.argsAs( + orElse: () => MyBooksRouteArgs( + filter: queryParams.optString( + 'filter', + 'none', + ))); + return _i6.MyBooksPage( + key: args.key, + filter: args.filter, + ); + }, + ); } class MyBooksRouteArgs { @@ -292,7 +234,12 @@ class ProfileRoute extends _i9.PageRouteInfo { static const String name = 'ProfileRoute'; - static const _i9.PageInfo page = _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return _i7.ProfilePage(); + }, + ); } /// generated route for @@ -306,7 +253,12 @@ class ProfileTab extends _i9.PageRouteInfo { static const String name = 'ProfileTab'; - static const _i9.PageInfo page = _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i3.ProfileTabPage(); + }, + ); } /// generated route for @@ -331,8 +283,29 @@ class SettingsTab extends _i9.PageRouteInfo { static const String name = 'SettingsTab'; - static const _i9.PageInfo page = - _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final queryParams = data.queryParams; + final args = data.argsAs( + orElse: () => SettingsTabArgs( + tab: pathParams.getString( + 'tab', + 'none', + ), + query: queryParams.getString( + 'query', + 'none', + ), + )); + return _i8.SettingsPage( + key: args.key, + tab: args.tab, + query: args.query, + ); + }, + ); } class SettingsTabArgs { @@ -365,5 +338,10 @@ class WelcomeRoute extends _i9.PageRouteInfo { static const String name = 'WelcomeRoute'; - static const _i9.PageInfo page = _i9.PageInfo(name); + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i4.WelcomeScreen(); + }, + ); } diff --git a/auto_route/example/lib/mobile/screens/settings_page.dart b/auto_route/example/lib/mobile/screens/settings_page.dart index 6f16043f..ed830f7f 100644 --- a/auto_route/example/lib/mobile/screens/settings_page.dart +++ b/auto_route/example/lib/mobile/screens/settings_page.dart @@ -46,7 +46,7 @@ class _SettingsPageState extends State ElevatedButton( onPressed: () { context.navigateTo(BooksTab( - children: [BookDetailsRoute(id: 2)], + children: [BookDetailsRoute(id: 1)], )); }, child: Text('Navigate to book details/1')) diff --git a/auto_route/example/lib/web_demo/router/web_router.dart b/auto_route/example/lib/web_demo/router/web_router.dart index 8ef17461..6e5a2432 100644 --- a/auto_route/example/lib/web_demo/router/web_router.dart +++ b/auto_route/example/lib/web_demo/router/web_router.dart @@ -1,29 +1,38 @@ + import 'package:auto_route/auto_route.dart'; import 'package:example/web_demo/router/web_router.gr.dart'; import 'package:example/web_demo/web_main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; + + + //ignore_for_file: public_member_api_docs @AutoRouterConfig(generateForDir: ['lib/web_demo']) -class WebAppRouter extends $WebAppRouter implements AutoRouteGuard { +class WebAppRouter extends RootStackRouter { AuthService authService; WebAppRouter(this.authService); @override - void onNavigation(NavigationResolver resolver, StackRouter router) async { - if (authService.isAuthenticated || - resolver.routeName == WebLoginRoute.name) { - resolver.next(); - } else { - resolver.redirect( - WebLoginRoute(onResult: (didLogin) { - resolver.resolveNext(didLogin, reevaluateNext: false); - }), - ); - } - } + late final List guards = [ + AutoRouteGuard.simple( + (resolver, scope) { + if (authService.isAuthenticated || resolver.routeName == WebLoginRoute.name) { + resolver.next(); + } else { + resolver.redirect( + WebLoginRoute(onResult: (didLogin) { + resolver.resolveNext(didLogin, reevaluateNext: false); + }), + ); + } + }, + ) + ]; + + @override List get routes => [ @@ -44,15 +53,13 @@ class WebAppRouter extends $WebAppRouter implements AutoRouteGuard { if (authService.isVerified) { resolver.next(); } else { - resolver - .redirect(WebVerifyRoute(onResult: resolver.next)); + resolver.redirect(WebVerifyRoute(onResult: resolver.next)); } }, ) ], children: [ - AutoRoute( - path: 'all', page: UserAllPostsRoute.page, initial: true), + AutoRoute(path: 'all', page: UserAllPostsRoute.page, initial: true), AutoRoute(path: 'favorite', page: UserFavoritePostsRoute.page), ], ), @@ -95,14 +102,17 @@ class _MainWebPageState extends State { padding: const EdgeInsets.symmetric(vertical: 16), child: ElevatedButton( onPressed: widget.navigate ?? - () { - context.pushRoute( - UserRoute( - id: 2, - query: const ['value1', 'value2'], - fragment: 'frag', - ), - ); + () async { + + final x = await MainWebRoute().push(context); + print(x); + // context.pushRoute( + // UserRoute( + // id: 2, + // query: const ['value1', 'value2'], + // fragment: 'frag', + // ), + // ); }, child: Text('Navigate to user/2'), ), @@ -111,7 +121,8 @@ class _MainWebPageState extends State { padding: const EdgeInsets.symmetric(vertical: 16), child: ElevatedButton( onPressed: () { - App.of(context).authService.isAuthenticated = false; + context.maybePop('String'); + // App.of(context).authService.isAuthenticated = false; }, child: Text('Logout'), ), @@ -119,8 +130,7 @@ class _MainWebPageState extends State { if (kIsWeb) ElevatedButton( onPressed: () { - final currentState = - ((context.router.pathState as int?) ?? 0); + final currentState = ((context.router.pathState as int?) ?? 0); context.router.pushPathState(currentState + 1); }, child: AnimatedBuilder( @@ -281,6 +291,7 @@ class UserPage extends StatefulWidget { final int id; final List? query; final String? fragment; + UserPage({ Key? key, @PathParam('userID') this.id = -1, @@ -301,8 +312,8 @@ class _UserPageState extends State { leading: AutoLeadingButton(), title: Builder( builder: (context) { - return Text(context.topRouteMatch.name + - ' ${widget.id} query: ${widget.query}, fragment: ${widget.fragment}'); + return Text( + context.topRouteMatch.name + ' ${widget.id} query: ${widget.query}, fragment: ${widget.fragment}'); }, ), ), diff --git a/auto_route/example/lib/web_demo/router/web_router.gr.dart b/auto_route/example/lib/web_demo/router/web_router.gr.dart index 18a3fe11..22c2876d 100644 --- a/auto_route/example/lib/web_demo/router/web_router.gr.dart +++ b/auto_route/example/lib/web_demo/router/web_router.gr.dart @@ -15,124 +15,6 @@ import 'package:example/web_demo/router/web_verify_page.dart' as _i3; import 'package:flutter/foundation.dart' as _i5; import 'package:flutter/material.dart' as _i6; -abstract class $WebAppRouter extends _i4.RootStackRouter { - $WebAppRouter({super.navigatorKey}); - - @override - final Map pagesMap = { - MainWebRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const MainWebRouteArgs()); - return _i4.AutoRoutePage( - routeData: routeData, - child: _i1.MainWebPage( - key: args.key, - navigate: args.navigate, - showUserPosts: args.showUserPosts, - ), - ); - }, - NotFoundRoute.name: (routeData) { - return _i4.AutoRoutePage( - routeData: routeData, - child: _i1.NotFoundScreen(), - ); - }, - UserAllPostsRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const UserAllPostsRouteArgs()); - return _i4.AutoRoutePage( - routeData: routeData, - child: _i1.UserAllPostsPage( - key: args.key, - navigate: args.navigate, - ), - ); - }, - UserFavoritePostsRoute.name: (routeData) { - return _i4.AutoRoutePage( - routeData: routeData, - child: _i1.UserFavoritePostsPage(), - ); - }, - UserRoute.name: (routeData) { - final pathParams = routeData.inheritedPathParams; - final queryParams = routeData.queryParams; - final args = routeData.argsAs( - orElse: () => UserRouteArgs( - id: pathParams.getInt( - 'userID', - -1, - ), - query: queryParams.optList('query'), - fragment: routeData.fragment, - )); - return _i4.AutoRoutePage( - routeData: routeData, - child: _i1.UserPage( - key: args.key, - id: args.id, - query: args.query, - fragment: args.fragment, - ), - ); - }, - UserPostsRoute.name: (routeData) { - final pathParams = routeData.inheritedPathParams; - return _i4.AutoRoutePage( - routeData: routeData, - child: _i1.UserPostsPage(id: pathParams.getInt('userID')), - ); - }, - UserProfileRoute.name: (routeData) { - final pathParams = routeData.inheritedPathParams; - final queryParams = routeData.queryParams; - final args = routeData.argsAs( - orElse: () => UserProfileRouteArgs( - userId: pathParams.getInt( - 'userID', - -1, - ), - likes: queryParams.getInt( - 'likes', - 0, - ), - )); - return _i4.AutoRoutePage( - routeData: routeData, - child: _i1.UserProfilePage( - key: args.key, - navigate: args.navigate, - userId: args.userId, - likes: args.likes, - ), - ); - }, - WebLoginRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const WebLoginRouteArgs()); - return _i4.AutoRoutePage( - routeData: routeData, - child: _i2.WebLoginPage( - key: args.key, - onResult: args.onResult, - ), - ); - }, - WebVerifyRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const WebVerifyRouteArgs()); - return _i4.AutoRoutePage( - routeData: routeData, - child: _i3.WebVerifyPage( - key: args.key, - onResult: args.onResult, - ), - ); - }, - }; -} - /// generated route for /// [_i1.MainWebPage] class MainWebRoute extends _i4.PageRouteInfo { @@ -153,8 +35,18 @@ class MainWebRoute extends _i4.PageRouteInfo { static const String name = 'MainWebRoute'; - static const _i4.PageInfo page = - _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = + data.argsAs(orElse: () => const MainWebRouteArgs()); + return _i1.MainWebPage( + key: args.key, + navigate: args.navigate, + showUserPosts: args.showUserPosts, + ); + }, + ); } class MainWebRouteArgs { @@ -187,7 +79,12 @@ class NotFoundRoute extends _i4.PageRouteInfo { static const String name = 'NotFoundRoute'; - static const _i4.PageInfo page = _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + return _i1.NotFoundScreen(); + }, + ); } /// generated route for @@ -208,8 +105,17 @@ class UserAllPostsRoute extends _i4.PageRouteInfo { static const String name = 'UserAllPostsRoute'; - static const _i4.PageInfo page = - _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const UserAllPostsRouteArgs()); + return _i1.UserAllPostsPage( + key: args.key, + navigate: args.navigate, + ); + }, + ); } class UserAllPostsRouteArgs { @@ -239,7 +145,12 @@ class UserFavoritePostsRoute extends _i4.PageRouteInfo { static const String name = 'UserFavoritePostsRoute'; - static const _i4.PageInfo page = _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + return _i1.UserFavoritePostsPage(); + }, + ); } /// generated route for @@ -267,8 +178,28 @@ class UserRoute extends _i4.PageRouteInfo { static const String name = 'UserRoute'; - static const _i4.PageInfo page = - _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final queryParams = data.queryParams; + final args = data.argsAs( + orElse: () => UserRouteArgs( + id: pathParams.getInt( + 'userID', + -1, + ), + query: queryParams.optList('query'), + fragment: data.fragment, + )); + return _i1.UserPage( + key: args.key, + id: args.id, + query: args.query, + fragment: args.fragment, + ); + }, + ); } class UserRouteArgs { @@ -304,7 +235,13 @@ class UserPostsRoute extends _i4.PageRouteInfo { static const String name = 'UserPostsRoute'; - static const _i4.PageInfo page = _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + return _i1.UserPostsPage(id: pathParams.getInt('userID')); + }, + ); } /// generated route for @@ -331,8 +268,30 @@ class UserProfileRoute extends _i4.PageRouteInfo { static const String name = 'UserProfileRoute'; - static const _i4.PageInfo page = - _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final queryParams = data.queryParams; + final args = data.argsAs( + orElse: () => UserProfileRouteArgs( + userId: pathParams.getInt( + 'userID', + -1, + ), + likes: queryParams.getInt( + 'likes', + 0, + ), + )); + return _i1.UserProfilePage( + key: args.key, + navigate: args.navigate, + userId: args.userId, + likes: args.likes, + ); + }, + ); } class UserProfileRouteArgs { @@ -375,8 +334,17 @@ class WebLoginRoute extends _i4.PageRouteInfo { static const String name = 'WebLoginRoute'; - static const _i4.PageInfo page = - _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const WebLoginRouteArgs()); + return _i2.WebLoginPage( + key: args.key, + onResult: args.onResult, + ); + }, + ); } class WebLoginRouteArgs { @@ -413,8 +381,17 @@ class WebVerifyRoute extends _i4.PageRouteInfo { static const String name = 'WebVerifyRoute'; - static const _i4.PageInfo page = - _i4.PageInfo(name); + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const WebVerifyRouteArgs()); + return _i3.WebVerifyPage( + key: args.key, + onResult: args.onResult, + ); + }, + ); } class WebVerifyRouteArgs { diff --git a/auto_route/example/lib/web_demo/web_main.dart b/auto_route/example/lib/web_demo/web_main.dart index ac361abe..481dc012 100644 --- a/auto_route/example/lib/web_demo/web_main.dart +++ b/auto_route/example/lib/web_demo/web_main.dart @@ -1,5 +1,5 @@ import 'package:auto_route/auto_route.dart'; -import 'package:example/web_demo/router/web_router.dart'; +import 'package:example/web_demo/router/web_router.gr.dart'; import 'package:flutter/material.dart'; //ignore_for_file: public_member_api_docs @@ -22,16 +22,19 @@ class AppState extends State { setState(() {}); }); - late final _appRouter = WebAppRouter(authService); + late final _router = AutoRouterRoot( + routes: [ + AutoRoute(page: MainWebRoute.page,initial: true), + ], + ); - List? urlRoutes; @override Widget build(BuildContext context) { return MaterialApp.router( theme: ThemeData.dark(), debugShowCheckedModeBanner: false, - routerConfig: _appRouter.config( + routerConfig: _router.config( reevaluateListenable: authService, ), ); diff --git a/auto_route/lib/auto_route.dart b/auto_route/lib/auto_route.dart index 898f1500..e0beb6fd 100644 --- a/auto_route/lib/auto_route.dart +++ b/auto_route/lib/auto_route.dart @@ -1,5 +1,7 @@ library auto_route; +import 'package:flutter/material.dart'; + export 'src/auto_router_module.dart'; export 'src/common/common.dart'; export 'src/matcher/route_match.dart'; @@ -24,3 +26,28 @@ export 'src/router/widgets/auto_tabs_router.dart'; export 'src/router/widgets/auto_tabs_scaffold.dart'; export 'src/router/widgets/custom_cupertino_transitions_builder.dart'; export 'src/router/widgets/deferred_widget.dart'; + +extension IterableX on Iterable? { + bool get isNullOrEmpty => this == null || this!.isEmpty; +} + +extension BoolX on bool? { + bool get isTrue => this == true; + + bool get isFalse => this == false; +} + + +extension StringGuardX on String? { + bool get isNullOrEmpty => this == null || this!.isEmpty; + bool get isNullOrBlank => this == null || this!.trim().isEmpty; + + T let(T Function(String str) block, T Function() orElse) => isNullOrEmpty ? orElse() : block(this!); +} + +void worker() { + String? name; + print(name.isNullOrBlank); + Widget nameWidget = name.let(Text.new, SizedBox.new); +} + diff --git a/auto_route/lib/src/matcher/route_match.dart b/auto_route/lib/src/matcher/route_match.dart index 1fac8ec3..9356dbce 100644 --- a/auto_route/lib/src/matcher/route_match.dart +++ b/auto_route/lib/src/matcher/route_match.dart @@ -87,6 +87,8 @@ class RouteMatch { /// Helper to access [AutoRoute.title] TitleBuilder? get titleBuilder => _config.title; + /// Helper to access [AutoRoute.buildPage] + AutoRoutePage buildPage(RouteData data) => _config.buildPage(data); /// Default constructor const RouteMatch({ required AutoRoute config, diff --git a/auto_route/lib/src/matcher/route_matcher.dart b/auto_route/lib/src/matcher/route_matcher.dart index 0f95f037..563b56c9 100644 --- a/auto_route/lib/src/matcher/route_matcher.dart +++ b/auto_route/lib/src/matcher/route_matcher.dart @@ -60,7 +60,7 @@ class RouteMatcher { match.pathParams.rawMap, ), ).path), - redirectedFrom: config.path, + redirectedFrom: config.path, ); } diff --git a/auto_route/lib/src/route/auto_route_config.dart b/auto_route/lib/src/route/auto_route_config.dart index c3c405a6..010afa66 100644 --- a/auto_route/lib/src/route/auto_route_config.dart +++ b/auto_route/lib/src/route/auto_route_config.dart @@ -4,6 +4,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; import 'package:meta/meta.dart'; +typedef AutoRoutePageBuilder = Widget Function(RouteData data); + /// Signature for a function that builds the route title /// Used in [AutoRoutePage] typedef TitleBuilder = String Function(BuildContext context, RouteData data); @@ -17,7 +19,7 @@ typedef RestorationIdBuilder = String Function(RouteMatch match); @immutable class AutoRoute { /// The name of page this route should map to - final String name; + final PageInfo page; final String? _path; /// Weather to match this route's path as fullMatch @@ -75,9 +77,25 @@ class AutoRoute { /// a RedirectRoute() to that path final bool initial; + /// Helper getter to get the name of the page + String get name => page.name; + + final AutoRoutePageBuilder _pageBuilder; + + /// Returns the Widget builder function of the page + AutoRoutePageBuilder get builder => _pageBuilder; + + /// Builds a [AutoRoutePage] from [RouteData] + AutoRoutePage buildPage(RouteData data) { + return AutoRoutePage( + child: builder(data), + routeData: data, + ); + } + AutoRoute._({ - required this.name, String? path, + required this.page, this.usesPathAsKey = false, this.guards = const [], this.fullMatch = false, @@ -92,12 +110,11 @@ class AutoRoute { this.initial = false, List? children, }) : _path = path, - _children = children != null && children.isNotEmpty - ? RouteCollection.fromList(children) - : null; + _pageBuilder = page.builder, + _children = children != null && children.isNotEmpty ? RouteCollection.fromList(children) : null; - const AutoRoute._change({ - required this.name, + AutoRoute._change({ + required this.page, required String path, required this.usesPathAsKey, required this.guards, @@ -113,6 +130,7 @@ class AutoRoute { required this.initial, required this.allowSnapshotting, }) : _path = path, + _pageBuilder = page.builder, _children = children; /// Builds a default AutoRoute instance with any [type] @@ -134,7 +152,7 @@ class AutoRoute { bool allowSnapshotting = true, }) { return AutoRoute._( - name: page.name, + page: page, path: path, fullMatch: fullMatch, maintainState: maintainState, @@ -172,7 +190,7 @@ class AutoRoute { bool allowSnapshotting = true, }) { return AutoRoute._( - name: page.name, + page: page, path: path, fullMatch: fullMatch, maintainState: maintainState, @@ -204,7 +222,7 @@ class AutoRoute { @override String toString() { - return 'RouteConfig{name: $name}'; + return 'AutoRoute{name: ${page.name}}'; } /// A simplified copyWith @@ -217,7 +235,7 @@ class AutoRoute { /// Returns a new AutoRoute instance with the provided details overriding. AutoRoute copyWith({ RouteType? type, - String? name, + PageInfo? page, String? path, bool? usesPathAsKey, List? guards, @@ -234,7 +252,7 @@ class AutoRoute { }) { return AutoRoute._change( type: type ?? this.type, - name: name ?? this.name, + page: page ?? this.page, path: path ?? this.path, usesPathAsKey: usesPathAsKey ?? this.usesPathAsKey, guards: guards ?? List.from(this.guards), @@ -243,9 +261,7 @@ class AutoRoute { meta: meta ?? this.meta, maintainState: maintainState ?? this.maintainState, fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog, - children: children != null - ? (children.isEmpty ? null : RouteCollection.fromList(children)) - : this.children, + children: children != null ? (children.isEmpty ? null : RouteCollection.fromList(children)) : this.children, //copy title: title ?? this.title, restorationId: restorationId ?? this.restorationId, @@ -268,10 +284,11 @@ class RedirectRoute extends AutoRoute { /// Default constructor RedirectRoute({ - required super.path, + required String path, required this.redirectTo, }) : super._( - name: 'Redirect#$path', + path: path, + page: PageInfo.redirect, fullMatch: true, ); } @@ -281,7 +298,7 @@ class RedirectRoute extends AutoRoute { class MaterialRoute extends AutoRoute { /// default constructor MaterialRoute({ - required PageInfo page, + required super.page, super.path, super.fullscreenDialog, super.maintainState, @@ -296,17 +313,16 @@ class MaterialRoute extends AutoRoute { super.initial, super.allowSnapshotting = true, }) : super._( - name: page.name, type: const RouteType.material(), ); } /// Builds an [AutoRoute] instance with [RouteType.cupertino] type @immutable -class CupertinoRoute extends AutoRoute { +class CupertinoRoute extends AutoRoute { /// Default constructor CupertinoRoute({ - required PageInfo page, + required super.page, super.fullscreenDialog, super.maintainState, super.fullMatch = false, @@ -320,15 +336,15 @@ class CupertinoRoute extends AutoRoute { super.keepHistory, super.initial, super.allowSnapshotting = true, - }) : super._(name: page.name, type: const RouteType.cupertino()); + }) : super._(type: const RouteType.cupertino()); } /// Builds an [AutoRoute] instance with [RouteType.adaptive] type @immutable -class AdaptiveRoute extends AutoRoute { +class AdaptiveRoute extends AutoRoute { /// Default constructor AdaptiveRoute({ - required PageInfo page, + required super.page, super.fullscreenDialog, super.maintainState, super.fullMatch = false, @@ -343,18 +359,15 @@ class AdaptiveRoute extends AutoRoute { bool opaque = true, super.keepHistory, super.allowSnapshotting = true, - }) : super._( - name: page.name, - type: RouteType.adaptive(opaque: opaque), - ); + }) : super._(type: RouteType.adaptive(opaque: opaque)); } /// Builds an [AutoRoute] instance with [RouteType.custom] type @immutable -class CustomRoute extends AutoRoute { +class CustomRoute extends AutoRoute { /// Default constructor CustomRoute({ - required PageInfo page, + required super.page, super.fullscreenDialog, super.maintainState, super.fullMatch = false, @@ -368,7 +381,7 @@ class CustomRoute extends AutoRoute { super.initial, super.allowSnapshotting = true, RouteTransitionsBuilder? transitionsBuilder, - CustomRouteBuilder? customRouteBuilder, + CustomRouteBuilder? customRouteBuilder, int? durationInMilliseconds, int? reverseDurationInMilliseconds, bool opaque = true, @@ -377,8 +390,7 @@ class CustomRoute extends AutoRoute { super.restorationId, Color? barrierColor, }) : super._( - name: page.name, - type: RouteType.custom( + type: CustomRouteType( transitionsBuilder: transitionsBuilder, customRouteBuilder: customRouteBuilder, durationInMilliseconds: durationInMilliseconds, @@ -402,7 +414,7 @@ class TestRoute extends AutoRoute { super.fullMatch, super.restorationId, super.initial, - }) : super._(name: name); + }) : super._(page: PageInfo(name, builder: (_) => const SizedBox())); } /// Builds a simplified [AutoRoute] instance for internal usage @@ -410,13 +422,12 @@ class TestRoute extends AutoRoute { @internal class DummyRootRoute extends AutoRoute { /// Default constructor - DummyRootRoute( - String name, { + DummyRootRoute({ required String path, super.children, super.fullMatch, super.restorationId, - }) : super._(name: name, path: path); + }) : super._(page: PageInfo.root, path: path); } /// Holds a single set of config-entries @@ -441,8 +452,7 @@ class RouteCollection { /// /// if this [RouteCollection] is created by the router [root] will be true /// else if it's created by a parent route-entry it will be false - factory RouteCollection.fromList(List routes, - {bool root = false}) { + factory RouteCollection.fromList(List routes, {bool root = false}) { final routesMarkedInitial = routes.where((e) => e.initial); throwIf(routesMarkedInitial.length > 1, 'Invalid data\nThere are more than one initial route in this collection\n${routesMarkedInitial.map((e) => e.name)}'); diff --git a/auto_route/lib/src/route/page_info.dart b/auto_route/lib/src/route/page_info.dart index 2bc173e1..c59b1c91 100644 --- a/auto_route/lib/src/route/page_info.dart +++ b/auto_route/lib/src/route/page_info.dart @@ -1,20 +1,43 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/cupertino.dart'; + /// Holds information of the generated [RoutePage] page /// /// Might hold more info in the future -class PageInfo { +class PageInfo { /// The name of the generated [RoutePage] final String name; + /// The builder function of the generated [RoutePage] + final Widget Function(RouteData data) builder; + /// Default constructor - const PageInfo(this.name); + const PageInfo(this.name, {required this.builder}); + @override bool operator ==(Object other) => identical(this, other) || - other is PageInfo && - runtimeType == other.runtimeType && - name == other.name; + other is PageInfo && runtimeType == other.runtimeType && builder == other.builder && name == other.name; @override - int get hashCode => name.hashCode; + int get hashCode => name.hashCode ^ builder.hashCode; + + /// Dummy [PageInfo] used to represent a redirect route + static final redirect = _NoBuilderPageInfo('#Redirect-Route'); + + /// Dummy [PageInfo] used to represent the root route + static final root = _NoBuilderPageInfo('#Root'); + +} + +/// Dummy [PageInfo] used to represent a redirect route +class _NoBuilderPageInfo extends PageInfo { + /// Default constructor + _NoBuilderPageInfo(super.name) + : super( + builder: (data) { + throw FlutterError('RedirectPageInfo does not have a builder'); + }, + ); } diff --git a/auto_route/lib/src/route/route_data.dart b/auto_route/lib/src/route/route_data.dart index c07f5c05..a092f338 100644 --- a/auto_route/lib/src/route/route_data.dart +++ b/auto_route/lib/src/route/route_data.dart @@ -185,4 +185,9 @@ class RouteData { } return _match; } + + /// Builds the [AutoRoutePage] page + AutoRoutePage buildPage() { + return _match.buildPage(this); + } } diff --git a/auto_route/lib/src/route/route_type.dart b/auto_route/lib/src/route/route_type.dart index 3122cd9b..f307028b 100644 --- a/auto_route/lib/src/route/route_type.dart +++ b/auto_route/lib/src/route/route_type.dart @@ -73,7 +73,7 @@ class AdaptiveRouteType extends RouteType { } /// Generates a route with user-defined transitions -class CustomRouteType extends RouteType { +class CustomRouteType extends RouteType { /// this builder function is passed to the transition builder /// function in [PageRouteBuilder] /// @@ -98,7 +98,7 @@ class CustomRouteType extends RouteType { /// this builder function accepts a BuildContext and a CustomPage /// that has all the other properties assigned to it /// so using them then is totally up to you. - final CustomRouteBuilder? customRouteBuilder; + final CustomRouteBuilder? customRouteBuilder; /// route transition duration in milliseconds /// is passed to [PageRouteBuilder] diff --git a/auto_route/lib/src/router/controller/root_stack_router.dart b/auto_route/lib/src/router/controller/root_stack_router.dart index 220b77e3..038e7684 100644 --- a/auto_route/lib/src/router/controller/root_stack_router.dart +++ b/auto_route/lib/src/router/controller/root_stack_router.dart @@ -10,10 +10,7 @@ typedef PageFactory = Page Function(RouteData data); /// An Implementation of [StackRouter] used by [AutoRouterDelegate] abstract class RootStackRouter extends StackRouter { /// Default constructor - RootStackRouter({super.navigatorKey}) - : super( - key: const ValueKey('Root'), - ) { + RootStackRouter({super.navigatorKey}) : super(key: const ValueKey('Root')) { _navigationHistory = NavigationHistory.create(this); } @@ -24,8 +21,7 @@ abstract class RootStackRouter extends StackRouter { DeepLinkBuilder? deepLinkBuilder, String? navRestorationScopeId, WidgetBuilder? placeholder, - NavigatorObserversBuilder navigatorObservers = - AutoRouterDelegate.defaultNavigatorObserversBuilder, + NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, bool includePrefixMatches = !kIsWeb, bool Function(String? location)? neglectWhen, bool rebuildStackOnDeepLink = false, @@ -57,7 +53,7 @@ abstract class RootStackRouter extends StackRouter { type: const RouteType.material(), stackKey: _stackKey, route: RouteMatch( - config: DummyRootRoute('Root', path: ''), + config: DummyRootRoute(path: ''), segments: const [''], stringMatch: '', key: const ValueKey('Root'), @@ -65,12 +61,13 @@ abstract class RootStackRouter extends StackRouter { pendingChildren: const [], ); - /// The map holding the page names and their factories - Map get pagesMap => throw UnimplementedError(); /// The list of route entries to match against List get routes; + /// A List of Root router guards + List get guards => const []; + /// The default animation RouteType get defaultRouteType => const RouteType.material(); @@ -94,22 +91,18 @@ abstract class RootStackRouter extends StackRouter { ); } - @override - PageBuilder get pageBuilder => _pageBuilder; AutoRouterDelegate? _lazyRootDelegate; /// Builds a lazy instance of [AutoRouterDelegate.declarative] - @Deprecated( - 'Declarative Root routing is not longer supported, Use route guards to conditionally navigate') + @Deprecated('Declarative Root routing is not longer supported, Use route guards to conditionally navigate') AutoRouterDelegate declarativeDelegate({ required RoutesBuilder routes, String? navRestorationScopeId, RoutePopCallBack? onPopRoute, OnNavigateCallBack? onNavigate, DeepLinkBuilder? deepLinkBuilder, - NavigatorObserversBuilder navigatorObservers = - AutoRouterDelegate.defaultNavigatorObserversBuilder, + NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, }) { return _lazyRootDelegate ??= AutoRouterDelegate.declarative( this, @@ -127,8 +120,7 @@ abstract class RootStackRouter extends StackRouter { AutoRouterDelegate delegate({ String? navRestorationScopeId, WidgetBuilder? placeholder, - NavigatorObserversBuilder navigatorObservers = - AutoRouterDelegate.defaultNavigatorObserversBuilder, + NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, DeepLinkBuilder? deepLinkBuilder, bool rebuildStackOnDeepLink = false, Listenable? reevaluateListenable, @@ -155,12 +147,6 @@ abstract class RootStackRouter extends StackRouter { deepLinkTransformer: deepLinkTransformer ?? (uri) async => uri, ); - AutoRoutePage _pageBuilder(RouteData data) { - var builder = pagesMap[data.name]; - assert(builder != null); - return builder!(data) as AutoRoutePage; - } - @override void updateRouteData(RouteData data) { throw FlutterError('Root RouteData should not update'); @@ -173,6 +159,27 @@ abstract class RootStackRouter extends StackRouter { NavigationHistory get navigationHistory => _navigationHistory; @override - late final RouteCollection routeCollection = - RouteCollection.fromList(routes, root: true); + late final RouteCollection routeCollection = RouteCollection.fromList(routes, root: true); } + + +/// A declarative implementation of [RootStackRouter] +class AutoRouterRoot extends RootStackRouter { + @override + final List routes; + + @override + final List guards; + + @override + final RouteType defaultRouteType; + + /// Default constructor + AutoRouterRoot({ + required this.routes, + this.guards = const [], + this.defaultRouteType = const RouteType.material(), + super.navigatorKey, + }); + +} \ No newline at end of file diff --git a/auto_route/lib/src/router/controller/routing_controller.dart b/auto_route/lib/src/router/controller/routing_controller.dart index f0aaebb7..8ec3d9ed 100644 --- a/auto_route/lib/src/router/controller/routing_controller.dart +++ b/auto_route/lib/src/router/controller/routing_controller.dart @@ -501,8 +501,6 @@ abstract class RoutingController with ChangeNotifier { ); } - /// The builder used to build routable pages - PageBuilder get pageBuilder; /// Clients can either pop their own [_pages] stack /// or defer the call to a parent controller @@ -644,8 +642,6 @@ class TabsRouter extends RoutingController { @override final RouteCollection routeCollection; @override - final PageBuilder pageBuilder; - @override final RouteMatcher matcher; RouteData _routeData; int _activeIndex = 0; @@ -661,7 +657,6 @@ class TabsRouter extends RoutingController { /// Default constructor TabsRouter( {required this.routeCollection, - required this.pageBuilder, required this.key, required RouteData routeData, this.homeIndex = -1, @@ -786,7 +781,7 @@ class TabsRouter extends RoutingController { for (var route in routes) { var data = _createRouteData(route, routeData); try { - _pages.add(pageBuilder(data)); + _pages.add(data.buildPage()) ; } on MissingRequiredParameterError catch (e) { if (fromDefault) { throw FlutterError( @@ -801,6 +796,8 @@ class TabsRouter extends RoutingController { } } + + @override List? _composeMatchesForReevaluate() { final matches = []; @@ -867,7 +864,7 @@ class TabsRouter extends RoutingController { } final data = _createRouteData(mayUpdateRoute, routeData); - _pages[pageToUpdateIndex] = pageBuilder(data); + _pages[pageToUpdateIndex] = data.buildPage(); final hasInitCtrl = _innerControllerOf(mayUpdateRoute.key) != null; @@ -1037,8 +1034,6 @@ abstract class StackRouter extends RoutingController { @override RouteCollection get routeCollection; - @override - PageBuilder get pageBuilder; @override RouteMatcher get matcher; @@ -1522,7 +1517,7 @@ abstract class StackRouter extends RoutingController { } routesToPush.add(match); final data = _createRouteData(match, routeData); - _pages.add(pageBuilder(data)); + _pages.add(data.buildPage()); } navigationHistory.onNewUrlState( @@ -1603,16 +1598,14 @@ abstract class StackRouter extends RoutingController { _removeRoute(topRoute._match, notify: false); } final data = _createRouteData(route, routeData); - final page = pageBuilder(data); + final page = data.buildPage(); _pages.add(page); if (notify) { notifyAll(); } - return (page as AutoRoutePage).popped; + return page.popped; } - late final AutoRouteGuard? _rootGuard = - (root is AutoRouteGuard) ? (root as AutoRouteGuard) : null; Future _canNavigate( RouteMatch route, { @@ -1620,8 +1613,9 @@ abstract class StackRouter extends RoutingController { List pendingRoutes = const [], bool isReevaluating = false, }) async { + final guards = [ - if (_rootGuard != null) _rootGuard!, + ...root.guards, ...route.guards, ]; if (guards.isEmpty) { @@ -1820,8 +1814,7 @@ class NestedStackRouter extends StackRouter { final RouteMatcher matcher; @override final RouteCollection routeCollection; - @override - final PageBuilder pageBuilder; + @override final bool managedByWidget; @@ -1830,7 +1823,6 @@ class NestedStackRouter extends StackRouter { /// Default constructor NestedStackRouter({ required this.routeCollection, - required this.pageBuilder, required super.key, required RouteData routeData, this.managedByWidget = false, diff --git a/auto_route/lib/src/router/widgets/auto_router.dart b/auto_route/lib/src/router/widgets/auto_router.dart index 9b150380..fe7fd2ec 100644 --- a/auto_route/lib/src/router/widgets/auto_router.dart +++ b/auto_route/lib/src/router/widgets/auto_router.dart @@ -35,8 +35,7 @@ class AutoRouter extends StatefulWidget { /// Default constructor const AutoRouter({ super.key, - this.navigatorObservers = - AutoRouterDelegate.defaultNavigatorObserversBuilder, + this.navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, this.builder, this.navRestorationScopeId, this.navigatorKey, @@ -48,8 +47,7 @@ class AutoRouter extends StatefulWidget { /// a declarative list of routes to update navigator stack static Widget declarative({ Key? key, - NavigatorObserversBuilder navigatorObservers = - AutoRouterDelegate.defaultNavigatorObserversBuilder, + NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, required RoutesBuilder routes, RoutePopCallBack? onPopRoute, String? navRestorationScopeId, @@ -82,8 +80,7 @@ class AutoRouter extends StatefulWidget { var scope = StackRouterScope.of(context, watch: watch); assert(() { if (scope == null) { - throw FlutterError( - 'AutoRouter operation requested with a context that does not include an AutoRouter.\n' + throw FlutterError('AutoRouter operation requested with a context that does not include an AutoRouter.\n' 'The context used to retrieve the Router must be that of a widget that ' 'is a descendant of an AutoRouter widget.'); } @@ -132,9 +129,7 @@ class AutoRouterState extends State { routeCollection: _parentController.routeCollection.subCollectionOf( parentRouteData.name, ), - pageBuilder: _parentController.pageBuilder, ); - _parentController.attachChildController(_controller!); _controller!.addListener(_rebuildListener); } @@ -198,8 +193,7 @@ class _DeclarativeAutoRouter extends StatefulWidget { const _DeclarativeAutoRouter({ required this.routes, - this.navigatorObservers = - AutoRouterDelegate.defaultNavigatorObserversBuilder, + this.navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, this.onPopRoute, this.navigatorKey, this.navRestorationScopeId, @@ -239,16 +233,16 @@ class _DeclarativeAutoRouterState extends State<_DeclarativeAutoRouter> { _navigatorObservers = _inheritableObserversBuilder(); _parentController = parentScope.controller; _controller = NestedStackRouter( - parent: _parentController, - key: parentData.key, - routeData: parentData, - managedByWidget: true, - onNavigate: widget.onNavigate, - navigatorKey: widget.navigatorKey, - routeCollection: _parentController.routeCollection.subCollectionOf( - parentData.name, - ), - pageBuilder: _parentController.pageBuilder); + parent: _parentController, + key: parentData.key, + routeData: parentData, + managedByWidget: true, + onNavigate: widget.onNavigate, + navigatorKey: widget.navigatorKey, + routeCollection: _parentController.routeCollection.subCollectionOf( + parentData.name, + ), + ); _parentController.attachChildController(_controller!); } } diff --git a/auto_route/lib/src/router/widgets/auto_tabs_router.dart b/auto_route/lib/src/router/widgets/auto_tabs_router.dart index 22fdd44d..c5cdee9b 100644 --- a/auto_route/lib/src/router/widgets/auto_tabs_router.dart +++ b/auto_route/lib/src/router/widgets/auto_tabs_router.dart @@ -195,7 +195,6 @@ abstract class AutoTabsRouterState extends State { routeCollection: _parentController.routeCollection.subCollectionOf( parentRoute.name, ), - pageBuilder: _parentController.pageBuilder, ); _parentController.attachChildController(_controller!); _setupController(); diff --git a/auto_route/test/main_router.gr.dart b/auto_route/test/main_router.gr.dart index 4576df5c..43bb24f8 100644 --- a/auto_route/test/main_router.gr.dart +++ b/auto_route/test/main_router.gr.dart @@ -12,144 +12,6 @@ part of 'main_router.dart'; abstract class _$MainRouter extends RootStackRouter { // ignore: unused_element _$MainRouter({super.navigatorKey}); - - @override - final Map pagesMap = { - DeclarativeRouterHostRoute.name: (routeData) { - final args = routeData.argsAs(); - return AutoRoutePage( - routeData: routeData, - child: DeclarativeRouterHostScreen( - key: args.key, - pageNotifier: args.pageNotifier, - ), - ); - }, - FirstRoute.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const FirstPage(), - ); - }, - FourthRoute.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const FourthPage(), - ); - }, - NotFoundRoute.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const NotFoundPage(), - ); - }, - SecondHostRoute.name: (routeData) { - final args = routeData.argsAs( - orElse: () => const SecondHostRouteArgs()); - return AutoRoutePage( - routeData: routeData, - child: SecondHostPage( - key: args.key, - useCustomLeading: args.useCustomLeading, - hasDrawer: args.hasDrawer, - ), - ); - }, - SecondNested1Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const SecondNested1Page(), - ); - }, - SecondNested2Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const SecondNested2Page(), - ); - }, - SecondNested3Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const SecondNested3Page(), - ); - }, - SecondRoute.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const SecondPage(), - ); - }, - Tab1Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const Tab1Page(), - ); - }, - Tab2Nested1Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const Tab2Nested1Page(), - ); - }, - Tab2Nested2Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const Tab2Nested2Page(), - ); - }, - Tab2Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const Tab2Page(), - ); - }, - Tab3Nested1Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const Tab3Nested1Page(), - ); - }, - Tab3Nested2Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const Tab3Nested2Page(), - ); - }, - Tab3Route.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const Tab3Page(), - ); - }, - TabsHostRoute.name: (routeData) { - final queryParams = routeData.queryParams; - final args = routeData.argsAs( - orElse: () => TabsHostRouteArgs( - tabsType: queryParams.getString( - 'tabsType', - 'IndexedStack', - ), - useDefaultRoutes: queryParams.getBool( - 'useDefaultRoutes', - false, - ), - )); - return AutoRoutePage( - routeData: routeData, - child: TabsHostPage( - key: args.key, - tabsType: args.tabsType, - useDefaultRoutes: args.useDefaultRoutes, - ), - ); - }, - ThirdRoute.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const ThirdPage(), - ); - }, - }; } /// generated route for @@ -171,8 +33,16 @@ class DeclarativeRouterHostRoute static const String name = 'DeclarativeRouterHostRoute'; - static const PageInfo page = - PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return DeclarativeRouterHostScreen( + key: args.key, + pageNotifier: args.pageNotifier, + ); + }, + ); } class DeclarativeRouterHostRouteArgs { @@ -202,7 +72,12 @@ class FirstRoute extends PageRouteInfo { static const String name = 'FirstRoute'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const FirstPage(); + }, + ); } /// generated route for @@ -216,7 +91,12 @@ class FourthRoute extends PageRouteInfo { static const String name = 'FourthRoute'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const FourthPage(); + }, + ); } /// generated route for @@ -230,7 +110,12 @@ class NotFoundRoute extends PageRouteInfo { static const String name = 'NotFoundRoute'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const NotFoundPage(); + }, + ); } /// generated route for @@ -253,8 +138,18 @@ class SecondHostRoute extends PageRouteInfo { static const String name = 'SecondHostRoute'; - static const PageInfo page = - PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const SecondHostRouteArgs()); + return SecondHostPage( + key: args.key, + useCustomLeading: args.useCustomLeading, + hasDrawer: args.hasDrawer, + ); + }, + ); } class SecondHostRouteArgs { @@ -287,7 +182,12 @@ class SecondNested1Route extends PageRouteInfo { static const String name = 'SecondNested1Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const SecondNested1Page(); + }, + ); } /// generated route for @@ -301,7 +201,12 @@ class SecondNested2Route extends PageRouteInfo { static const String name = 'SecondNested2Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const SecondNested2Page(); + }, + ); } /// generated route for @@ -315,7 +220,12 @@ class SecondNested3Route extends PageRouteInfo { static const String name = 'SecondNested3Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const SecondNested3Page(); + }, + ); } /// generated route for @@ -329,7 +239,12 @@ class SecondRoute extends PageRouteInfo { static const String name = 'SecondRoute'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const SecondPage(); + }, + ); } /// generated route for @@ -343,7 +258,12 @@ class Tab1Route extends PageRouteInfo { static const String name = 'Tab1Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const Tab1Page(); + }, + ); } /// generated route for @@ -357,7 +277,12 @@ class Tab2Nested1Route extends PageRouteInfo { static const String name = 'Tab2Nested1Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const Tab2Nested1Page(); + }, + ); } /// generated route for @@ -371,7 +296,12 @@ class Tab2Nested2Route extends PageRouteInfo { static const String name = 'Tab2Nested2Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const Tab2Nested2Page(); + }, + ); } /// generated route for @@ -385,7 +315,12 @@ class Tab2Route extends PageRouteInfo { static const String name = 'Tab2Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const Tab2Page(); + }, + ); } /// generated route for @@ -399,7 +334,12 @@ class Tab3Nested1Route extends PageRouteInfo { static const String name = 'Tab3Nested1Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const Tab3Nested1Page(); + }, + ); } /// generated route for @@ -413,7 +353,12 @@ class Tab3Nested2Route extends PageRouteInfo { static const String name = 'Tab3Nested2Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const Tab3Nested2Page(); + }, + ); } /// generated route for @@ -427,7 +372,12 @@ class Tab3Route extends PageRouteInfo { static const String name = 'Tab3Route'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const Tab3Page(); + }, + ); } /// generated route for @@ -454,8 +404,28 @@ class TabsHostRoute extends PageRouteInfo { static const String name = 'TabsHostRoute'; - static const PageInfo page = - PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + final queryParams = data.queryParams; + final args = data.argsAs( + orElse: () => TabsHostRouteArgs( + tabsType: queryParams.getString( + 'tabsType', + 'IndexedStack', + ), + useDefaultRoutes: queryParams.getBool( + 'useDefaultRoutes', + false, + ), + )); + return TabsHostPage( + key: args.key, + tabsType: args.tabsType, + useDefaultRoutes: args.useDefaultRoutes, + ); + }, + ); } class TabsHostRouteArgs { @@ -488,5 +458,10 @@ class ThirdRoute extends PageRouteInfo { static const String name = 'ThirdRoute'; - static const PageInfo page = PageInfo(name); + static PageInfo page = PageInfo( + name, + builder: (data) { + return const ThirdPage(); + }, + ); } diff --git a/auto_route/test/page_info_test.dart b/auto_route/test/page_info_test.dart deleted file mode 100644 index 4db4cc4c..00000000 --- a/auto_route/test/page_info_test.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("PageInfo equality test", () { - expect(const PageInfo('Name') == const PageInfo('Name'), true); - }); -} diff --git a/auto_route_generator/lib/src/code_builder/library_builder.dart b/auto_route_generator/lib/src/code_builder/library_builder.dart index ee4cfe4e..54add903 100644 --- a/auto_route_generator/lib/src/code_builder/library_builder.dart +++ b/auto_route_generator/lib/src/code_builder/library_builder.dart @@ -7,7 +7,6 @@ import '../models/route_config.dart'; import '../models/router_config.dart'; import 'deferred_pages_allocator.dart'; import 'route_info_builder.dart'; -import 'router_config_builder.dart'; /// AutoRoute imports const autoRouteImport = 'package:auto_route/auto_route.dart'; @@ -68,7 +67,6 @@ String generateLibrary( for (final ignore in ignoreForFile) "ignore_for_file: $ignore", ]) ..body.addAll([ - buildRouterConfig(router, routes), if (routes.isNotEmpty) ...routes .distinctBy((e) => e.getName(router.replaceInRouteName)) diff --git a/auto_route_generator/lib/src/code_builder/route_info_builder.dart b/auto_route_generator/lib/src/code_builder/route_info_builder.dart index 41818a22..f8ed0b25 100644 --- a/auto_route_generator/lib/src/code_builder/route_info_builder.dart +++ b/auto_route_generator/lib/src/code_builder/route_info_builder.dart @@ -7,35 +7,23 @@ import 'library_builder.dart'; import 'package:collection/collection.dart'; /// Builds a route info class and args class for the given [RouteConfig] -List buildRouteInfoAndArgs( - RouteConfig r, RouterConfig router, DartEmitter emitter) { +List buildRouteInfoAndArgs(RouteConfig r, RouterConfig router, DartEmitter emitter) { final argsClassRefer = refer('${r.getName(router.replaceInRouteName)}Args'); final parameters = r.parameters; - final fragmentParam = parameters.firstWhereOrNull((e)=> e.isUrlFragment); - final nonInheritedParameters = - parameters.where((p) => !p.isInheritedPathParam).toList(); - final pageInfoRefer = TypeReference( - (b) => b - ..url = autoRouteImport - ..symbol = 'PageInfo' - ..types.add( - (nonInheritedParameters.isNotEmpty) ? argsClassRefer : refer('void')), - ); + final fragmentParam = parameters.firstWhereOrNull((e) => e.isUrlFragment); + final nonInheritedParameters = parameters.where((p) => !p.isInheritedPathParam).toList(); + final pageInfoRefer = refer('PageInfo', autoRouteImport); return [ Class( (b) => b - ..docs.addAll([ - '/// generated route for \n/// [${r.pageType?.refer.accept(emitter).toString()}]' - ]) + ..docs.addAll(['/// generated route for \n/// [${r.pageType?.refer.accept(emitter).toString()}]']) ..name = r.getName(router.replaceInRouteName) ..extend = TypeReference((b) { b ..symbol = 'PageRouteInfo' ..url = autoRouteImport ..types.add( - (nonInheritedParameters.isNotEmpty) - ? argsClassRefer - : refer('void'), + (nonInheritedParameters.isNotEmpty) ? argsClassRefer : refer('void'), ); }) ..fields.addAll([ @@ -45,16 +33,14 @@ List buildRouteInfoAndArgs( ..name = 'name' ..static = true ..type = stringRefer - ..assignment = - literalString(r.getName(router.replaceInRouteName)).code, + ..assignment = literalString(r.getName(router.replaceInRouteName)).code, ), Field( (b) => b - ..modifier = FieldModifier.constant ..name = 'page' ..static = true ..type = pageInfoRefer - ..assignment = pageInfoRefer.newInstance([refer('name')]).code, + ..assignment = pageInfoRefer.newInstance([refer('name')], {'builder': _buildMethod(r, router)}).code, ), ]) ..constructors.add( @@ -63,8 +49,7 @@ List buildRouteInfoAndArgs( b ..constant = parameters.isEmpty ..optionalParameters.addAll([ - ...buildArgParams(nonInheritedParameters, emitter, - toThis: false), + ...buildArgParams(nonInheritedParameters, emitter, toThis: false), Parameter((b) => b ..named = true ..name = 'children' @@ -107,8 +92,7 @@ List buildRouteInfoAndArgs( ), ), ), - if(fragmentParam != null) - 'fragment': refer(fragmentParam.name), + if (fragmentParam != null) 'fragment': refer(fragmentParam.name), 'initialChildren': refer('children'), }).code); }, @@ -123,9 +107,7 @@ List buildRouteInfoAndArgs( ...nonInheritedParameters.map((param) => Field((b) => b ..modifier = FieldModifier.final$ ..name = param.name - ..type = param is FunctionParamConfig - ? param.funRefer - : param.type.refer)), + ..type = param is FunctionParamConfig ? param.funRefer : param.type.refer)), ]) ..constructors.add( Constructor((b) => b @@ -151,9 +133,7 @@ List buildRouteInfoAndArgs( } /// Builds a list of [Parameter]s from the given [parameters] -Iterable buildArgParams( - List parameters, DartEmitter emitter, - {bool toThis = true}) { +Iterable buildArgParams(List parameters, DartEmitter emitter, {bool toThis = true}) { return parameters.map( (p) => Parameter( (b) { @@ -172,9 +152,111 @@ Iterable buildArgParams( ..toThis = toThis ..required = p.isRequired || p.isPositional ..defaultTo = defaultCode; - if (!toThis) - b.type = p is FunctionParamConfig ? p.funRefer : p.type.refer; + if (!toThis) b.type = p is FunctionParamConfig ? p.funRefer : p.type.refer; }, ), ); } + +Expression _buildMethod(RouteConfig r, RouterConfig router) { + final useConsConstructor = r.hasConstConstructor && !(r.deferredLoading ?? router.deferredLoading); + var constructedPage = useConsConstructor ? r.pageType!.refer.constInstance([]) : _getPageInstance(r); + + if (r.hasWrappedRoute == true) { + constructedPage = refer('WrappedRoute', autoRouteImport).newInstance( + [], + {'child': constructedPage}, + ); + } + + if ((r.deferredLoading ?? router.deferredLoading) && r.pageType != null) { + constructedPage = _getDeferredBuilder(r, constructedPage); + } + final inheritedParameters = r.parameters.where((p) => p.isInheritedPathParam); + + final nonInheritedParameters = r.parameters.where((p) => !p.isInheritedPathParam); + return Method( + (b) => b + ..requiredParameters.add( + Parameter((b) => b.name = 'data'), + ) + ..body = Block((b) => b.statements.addAll([ + if ((!r.hasUnparsableRequiredArgs) && r.parameters.any((p) => p.isPathParam) || + inheritedParameters.isNotEmpty) + declareFinal('pathParams').assign(refer('data').property('inheritedPathParams')).statement, + if (!r.hasUnparsableRequiredArgs && r.parameters.any((p) => p.isQueryParam)) + declareFinal('queryParams').assign(refer('data').property('queryParams')).statement, + if (nonInheritedParameters.isNotEmpty) + declareFinal('args') + .assign( + refer('data').property('argsAs').call([], { + if (!r.hasUnparsableRequiredArgs) + 'orElse': Method( + (b) => b + ..lambda = true + ..body = r.pathQueryParams.isEmpty + ? refer('${r.getName(router.replaceInRouteName)}Args').constInstance([]).code + : refer('${r.getName(router.replaceInRouteName)}Args').newInstance( + [], + Map.fromEntries( + nonInheritedParameters + .where((p) => (p.isPathParam || p.isQueryParam || p.isUrlFragment)) + .map( + (p) => MapEntry( + p.name, + _getUrlPartAssignment(p), + ), + ), + ), + ).code, + ).closure + }, [ + refer('${r.getName(router.replaceInRouteName)}Args'), + ]), + ) + .statement, + constructedPage.returned.statement + ])), + ).closure; +} + +Expression _getDeferredBuilder(RouteConfig r, Expression page) { + return TypeReference((b) => b + ..symbol = 'DeferredWidget' + ..url = autoRouteImport).newInstance([ + TypeReference((b) => b + ..symbol = 'loadLibrary' + ..url = r.pageType!.refer.url), + Method((b) => b..body = page.code).closure + ]); +} + +Expression _getPageInstance(RouteConfig r) { + return r.pageType!.refer.newInstance( + r.positionalParams.map((p) { + return refer('args').property(p.name); + }), + Map.fromEntries(r.namedParams.map( + (p) => MapEntry( + p.name, + p.isInheritedPathParam ? _getUrlPartAssignment(p) : refer('args').property(p.name), + ), + )), + ); +} + +Expression _getUrlPartAssignment(ParamConfig p) { + if (p.isPathParam) { + return refer('pathParams').property(p.getterMethodName).call([ + literalString(p.paramName), + if (p.defaultValueCode != null) refer(p.defaultValueCode!), + ]); + } else if (p.isQueryParam) { + return refer('queryParams').property(p.getterMethodName).call([ + literalString(p.paramName), + if (p.defaultValueCode != null) refer(p.defaultValueCode!), + ]); + } else { + return refer('data').property('fragment'); + } +} diff --git a/auto_route_generator/lib/src/code_builder/router_config_builder.dart b/auto_route_generator/lib/src/code_builder/router_config_builder.dart deleted file mode 100644 index 2cbb8bf7..00000000 --- a/auto_route_generator/lib/src/code_builder/router_config_builder.dart +++ /dev/null @@ -1,218 +0,0 @@ -import 'package:code_builder/code_builder.dart'; - -import '../../utils.dart'; -import '../models/route_config.dart'; -import '../models/route_parameter_config.dart'; -import '../models/router_config.dart'; -import 'library_builder.dart'; - -/// Builds a router config class for the given [RouterConfig] -Class buildRouterConfig(RouterConfig router, List routes) => Class( - (b) => b - ..name = - '${router.usesPartBuilder ? '_' : ''}\$${router.routerClassName}' - ..abstract = true - ..extend = refer( - router.isModule ? 'AutoRouterModule' : 'RootStackRouter', - autoRouteImport, - ) - ..fields.addAll([_buildPagesMap(routes, router)]) - ..constructors.addAll(router.isModule - ? [] - : [ - Constructor((b) => b - ..docs.addAll( - [if (router.usesPartBuilder) '// ignore: unused_element']) - ..optionalParameters.add( - Parameter((b) => b - ..name = 'navigatorKey' - ..named = true - ..toSuper = true), - )), - ]), - ); - -Field _buildPagesMap(List routes, RouterConfig router) { - return Field( - (b) => b - ..name = "pagesMap" - ..modifier = FieldModifier.final$ - ..annotations.add(refer('override')) - ..type = TypeReference( - (b) => b - ..symbol = 'Map' - ..types.addAll([ - stringRefer, - refer('PageFactory', autoRouteImport), - ]), - ) - ..assignment = _buildAssignment(routes, router), - ); -} - -/// Builds the map assignment for the pagesMap field -Code _buildAssignment(List routes, RouterConfig router) { - final effectiveRoutes = - routes.distinctBy((e) => e.getName(router.replaceInRouteName)).map( - (r) => MapEntry( - refer(r.getName(router.replaceInRouteName)).property('name'), - _buildMethod(r, router), - ), - ); - final modules = router.modules; - - if (modules.isEmpty) { - return literalMap(Map.fromEntries(effectiveRoutes)).code; - } - - return Block.of([ - Code('{'), - for (final route in effectiveRoutes) ...[ - route.key.code, - Code(':'), - route.value.code, - Code(',') - ], - for (final module in modules) ...[ - refer(module.name, module.import) - .newInstance([]) - .property('pagesMap') - .spread - .code, - Code(',') - ], - Code('}'), - ]); -} - -Expression _buildMethod(RouteConfig r, RouterConfig router) { - final useConsConstructor = - r.hasConstConstructor && !(r.deferredLoading ?? router.deferredLoading); - var constructedPage = useConsConstructor - ? r.pageType!.refer.constInstance([]) - : _getPageInstance(r); - - if (r.hasWrappedRoute == true) { - constructedPage = refer('WrappedRoute', autoRouteImport).newInstance( - [], - {'child': constructedPage}, - ); - } - - if ((r.deferredLoading ?? router.deferredLoading) && r.pageType != null) { - constructedPage = _getDeferredBuilder(r, constructedPage); - } - final inheritedParameters = r.parameters.where((p) => p.isInheritedPathParam); - - final nonInheritedParameters = - r.parameters.where((p) => !p.isInheritedPathParam); - return Method( - (b) => b - ..requiredParameters.add( - Parameter((b) => b.name = 'routeData'), - ) - ..body = Block((b) => b.statements.addAll([ - if ((!r.hasUnparsableRequiredArgs) && - r.parameters.any((p) => p.isPathParam) || - inheritedParameters.isNotEmpty) - declareFinal('pathParams') - .assign(refer('routeData').property('inheritedPathParams')) - .statement, - if (!r.hasUnparsableRequiredArgs && - r.parameters.any((p) => p.isQueryParam)) - declareFinal('queryParams') - .assign(refer('routeData').property('queryParams')) - .statement, - if (nonInheritedParameters.isNotEmpty) - declareFinal('args') - .assign( - refer('routeData').property('argsAs').call([], { - if (!r.hasUnparsableRequiredArgs) - 'orElse': Method( - (b) => b - ..lambda = true - ..body = r.pathQueryParams.isEmpty - ? refer('${r.getName(router.replaceInRouteName)}Args') - .constInstance([]).code - : refer('${r.getName(router.replaceInRouteName)}Args') - .newInstance( - [], - Map.fromEntries( - nonInheritedParameters - .where((p) => - (p.isPathParam || p.isQueryParam || p.isUrlFragment)) - .map( - (p) => MapEntry( - p.name, - _getUrlPartAssignment(p), - ), - ), - ), - ).code, - ).closure - }, [ - refer('${r.getName(router.replaceInRouteName)}Args'), - ]), - ) - .statement, - TypeReference( - (b) => b - ..symbol = 'AutoRoutePage' - ..url = autoRouteImport - ..types.add(r.returnType?.refer ?? refer('dynamic')), - ) - .newInstance( - [], - { - 'routeData': refer('routeData'), - 'child': constructedPage, - }, - ) - .returned - .statement - ])), - ).closure; -} - -Expression _getDeferredBuilder(RouteConfig r, Expression page) { - return TypeReference((b) => b - ..symbol = 'DeferredWidget' - ..url = autoRouteImport).newInstance([ - TypeReference((b) => b - ..symbol = 'loadLibrary' - ..url = r.pageType!.refer.url), - Method((b) => b..body = page.code).closure - ]); -} - -Expression _getPageInstance(RouteConfig r) { - return r.pageType!.refer.newInstance( - r.positionalParams.map((p) { - return refer('args').property(p.name); - }), - Map.fromEntries(r.namedParams.map( - (p) => MapEntry( - p.name, - p.isInheritedPathParam - ? _getUrlPartAssignment(p) - : refer('args').property(p.name), - ), - )), - ); -} - -Expression _getUrlPartAssignment(ParamConfig p) { - if (p.isPathParam) { - return refer('pathParams').property(p.getterMethodName).call([ - literalString(p.paramName), - if (p.defaultValueCode != null) refer(p.defaultValueCode!), - ]); - } else if(p.isQueryParam) { - return refer('queryParams').property(p.getterMethodName).call([ - literalString(p.paramName), - if (p.defaultValueCode != null) refer(p.defaultValueCode!), - ]); - }else{ - return refer('routeData').property('fragment'); - } -} From f869e2e9ea4bea15b1431e5df3ec43239f6b3403 Mon Sep 17 00:00:00 2001 From: milad Date: Sun, 28 Jul 2024 21:28:12 +0300 Subject: [PATCH 02/13] Add proxy to build empty router shells remove deprecated code remove module implementation as there is no need for it any more --- .../example/lib/mobile/router/router.dart | 17 +-- .../example/lib/mobile/router/router.gr.dart | 137 +++++++----------- .../example/lib/mobile/screens/home_page.dart | 2 + .../mobile/screens/profile/my_books_page.dart | 2 +- .../lib/mobile/screens/profile/routes.dart | 1 + .../lib/mobile/screens/settings_page.dart | 1 + .../lib/web_demo/router/web_router.dart | 27 ++-- auto_route/example/lib/web_demo/web_main.dart | 11 +- auto_route/lib/auto_route.dart | 28 ---- auto_route/lib/src/auto_router_module.dart | 8 - .../src/common/auto_route_annotations.dart | 24 +-- auto_route/lib/src/matcher/route_match.dart | 1 + auto_route/lib/src/matcher/route_matcher.dart | 2 +- .../lib/src/route/auto_route_config.dart | 12 +- auto_route/lib/src/route/page_info.dart | 7 +- auto_route/lib/src/route/page_route_info.dart | 20 +++ auto_route/lib/src/route/route_data.dart | 2 +- auto_route/lib/src/router/auto_router_x.dart | 6 - .../controller/auto_router_delegate.dart | 102 ------------- .../router/controller/root_stack_router.dart | 58 +------- .../router/controller/routing_controller.dart | 27 +--- .../lib/src/router/widgets/auto_router.dart | 12 +- .../custom_cupertino_transitions_builder.dart | 110 ++------------ auto_route/test/parameters_test.dart | 7 +- .../builders/auto_router_builder_base.dart | 5 +- .../lib/src/models/route_config.dart | 7 - .../lib/src/models/router_config.dart | 15 +- .../src/resolvers/route_config_resolver.dart | 9 -- .../src/resolvers/router_config_resolver.dart | 18 +-- 29 files changed, 150 insertions(+), 528 deletions(-) delete mode 100644 auto_route/lib/src/auto_router_module.dart diff --git a/auto_route/example/lib/mobile/router/router.dart b/auto_route/example/lib/mobile/router/router.dart index 15c8dff5..d3495881 100644 --- a/auto_route/example/lib/mobile/router/router.dart +++ b/auto_route/example/lib/mobile/router/router.dart @@ -3,14 +3,14 @@ import 'package:auto_route/auto_route.dart'; import 'package:example/mobile/router/router.gr.dart'; import 'package:example/mobile/screens/profile/routes.dart'; + @AutoRouterConfig(generateForDir: ['lib/mobile']) class AppRouter extends RootStackRouter { @override final List routes = [ - AutoRoute(page: WelcomeRoute.page, initial: true), AutoRoute( page: HomeRoute.page, - path: '/home', + initial: true, children: [ AutoRoute( path: 'books', @@ -38,17 +38,12 @@ class AppRouter extends RootStackRouter { ), ], ), - AutoRoute(page: LoginRoute.page, path: '/login'), + AutoRoute(page: BooksTab.page, path: '/login'), RedirectRoute(path: '*', redirectTo: '/'), ]; } -@RoutePage(name: 'BooksTab') -class BooksTabPage extends AutoRouter { - const BooksTabPage({super.key}); -} +final BooksTab = EmptyShellRoute('BooksTab'); +final ProfileTab = EmptyShellRoute('ProfileTab'); + -@RoutePage(name: 'ProfileTab') -class ProfileTabPage extends AutoRouter { - const ProfileTabPage({super.key}); -} diff --git a/auto_route/example/lib/mobile/router/router.gr.dart b/auto_route/example/lib/mobile/router/router.gr.dart index 0a38a50d..18ab4f1c 100644 --- a/auto_route/example/lib/mobile/router/router.gr.dart +++ b/auto_route/example/lib/mobile/router/router.gr.dart @@ -8,23 +8,22 @@ // coverage:ignore-file // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:auto_route/auto_route.dart' as _i9; -import 'package:example/mobile/router/router.dart' as _i3; +import 'package:auto_route/auto_route.dart' as _i8; import 'package:example/mobile/screens/books/book_details_page.dart' as _i1; import 'package:example/mobile/screens/books/book_list_page.dart' as _i2; -import 'package:example/mobile/screens/home_page.dart' as _i4; -import 'package:example/mobile/screens/login_page.dart' as _i5; -import 'package:example/mobile/screens/profile/my_books_page.dart' as _i6; -import 'package:example/mobile/screens/profile/profile_page.dart' as _i7; -import 'package:example/mobile/screens/settings_page.dart' as _i8; -import 'package:flutter/material.dart' as _i10; +import 'package:example/mobile/screens/home_page.dart' as _i3; +import 'package:example/mobile/screens/login_page.dart' as _i4; +import 'package:example/mobile/screens/profile/my_books_page.dart' as _i5; +import 'package:example/mobile/screens/profile/profile_page.dart' as _i6; +import 'package:example/mobile/screens/settings_page.dart' as _i7; +import 'package:flutter/material.dart' as _i9; /// generated route for /// [_i1.BookDetailsPage] -class BookDetailsRoute extends _i9.PageRouteInfo { +class BookDetailsRoute extends _i8.PageRouteInfo { BookDetailsRoute({ int id = -3, - List<_i9.PageRouteInfo>? children, + List<_i8.PageRouteInfo>? children, }) : super( BookDetailsRoute.name, args: BookDetailsRouteArgs(id: id), @@ -34,7 +33,7 @@ class BookDetailsRoute extends _i9.PageRouteInfo { static const String name = 'BookDetailsRoute'; - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { final pathParams = data.inheritedPathParams; @@ -62,8 +61,8 @@ class BookDetailsRouteArgs { /// generated route for /// [_i2.BookListScreen] -class BookListRoute extends _i9.PageRouteInfo { - const BookListRoute({List<_i9.PageRouteInfo>? children}) +class BookListRoute extends _i8.PageRouteInfo { + const BookListRoute({List<_i8.PageRouteInfo>? children}) : super( BookListRoute.name, initialChildren: children, @@ -71,7 +70,7 @@ class BookListRoute extends _i9.PageRouteInfo { static const String name = 'BookListRoute'; - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { return _i2.BookListScreen(); @@ -80,28 +79,9 @@ class BookListRoute extends _i9.PageRouteInfo { } /// generated route for -/// [_i3.BooksTabPage] -class BooksTab extends _i9.PageRouteInfo { - const BooksTab({List<_i9.PageRouteInfo>? children}) - : super( - BooksTab.name, - initialChildren: children, - ); - - static const String name = 'BooksTab'; - - static _i9.PageInfo page = _i9.PageInfo( - name, - builder: (data) { - return const _i3.BooksTabPage(); - }, - ); -} - -/// generated route for -/// [_i4.HomePage] -class HomeRoute extends _i9.PageRouteInfo { - const HomeRoute({List<_i9.PageRouteInfo>? children}) +/// [_i3.HomePage] +class HomeRoute extends _i8.PageRouteInfo { + const HomeRoute({List<_i8.PageRouteInfo>? children}) : super( HomeRoute.name, initialChildren: children, @@ -109,22 +89,22 @@ class HomeRoute extends _i9.PageRouteInfo { static const String name = 'HomeRoute'; - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { - return const _i4.HomePage(); + return const _i3.HomePage(); }, ); } /// generated route for -/// [_i5.LoginPage] -class LoginRoute extends _i9.PageRouteInfo { +/// [_i4.LoginPage] +class LoginRoute extends _i8.PageRouteInfo { LoginRoute({ - _i10.Key? key, + _i9.Key? key, void Function(bool)? onLoginResult, bool showBackButton = true, - List<_i9.PageRouteInfo>? children, + List<_i8.PageRouteInfo>? children, }) : super( LoginRoute.name, args: LoginRouteArgs( @@ -137,12 +117,12 @@ class LoginRoute extends _i9.PageRouteInfo { static const String name = 'LoginRoute'; - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { final args = data.argsAs(orElse: () => const LoginRouteArgs()); - return _i5.LoginPage( + return _i4.LoginPage( key: args.key, onLoginResult: args.onLoginResult, showBackButton: args.showBackButton, @@ -158,7 +138,7 @@ class LoginRouteArgs { this.showBackButton = true, }); - final _i10.Key? key; + final _i9.Key? key; final void Function(bool)? onLoginResult; @@ -171,12 +151,12 @@ class LoginRouteArgs { } /// generated route for -/// [_i6.MyBooksPage] -class MyBooksRoute extends _i9.PageRouteInfo { +/// [_i5.MyBooksPage] +class MyBooksRoute extends _i8.PageRouteInfo { MyBooksRoute({ - _i10.Key? key, + _i9.Key? key, String? filter = 'none', - List<_i9.PageRouteInfo>? children, + List<_i8.PageRouteInfo>? children, }) : super( MyBooksRoute.name, args: MyBooksRouteArgs( @@ -189,7 +169,7 @@ class MyBooksRoute extends _i9.PageRouteInfo { static const String name = 'MyBooksRoute'; - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { final queryParams = data.queryParams; @@ -199,7 +179,7 @@ class MyBooksRoute extends _i9.PageRouteInfo { 'filter', 'none', ))); - return _i6.MyBooksPage( + return _i5.MyBooksPage( key: args.key, filter: args.filter, ); @@ -213,7 +193,7 @@ class MyBooksRouteArgs { this.filter = 'none', }); - final _i10.Key? key; + final _i9.Key? key; final String? filter; @@ -224,9 +204,9 @@ class MyBooksRouteArgs { } /// generated route for -/// [_i7.ProfilePage] -class ProfileRoute extends _i9.PageRouteInfo { - const ProfileRoute({List<_i9.PageRouteInfo>? children}) +/// [_i6.ProfilePage] +class ProfileRoute extends _i8.PageRouteInfo { + const ProfileRoute({List<_i8.PageRouteInfo>? children}) : super( ProfileRoute.name, initialChildren: children, @@ -234,41 +214,22 @@ class ProfileRoute extends _i9.PageRouteInfo { static const String name = 'ProfileRoute'; - static _i9.PageInfo page = _i9.PageInfo( - name, - builder: (data) { - return _i7.ProfilePage(); - }, - ); -} - -/// generated route for -/// [_i3.ProfileTabPage] -class ProfileTab extends _i9.PageRouteInfo { - const ProfileTab({List<_i9.PageRouteInfo>? children}) - : super( - ProfileTab.name, - initialChildren: children, - ); - - static const String name = 'ProfileTab'; - - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { - return const _i3.ProfileTabPage(); + return _i6.ProfilePage(); }, ); } /// generated route for -/// [_i8.SettingsPage] -class SettingsTab extends _i9.PageRouteInfo { +/// [_i7.SettingsPage] +class SettingsTab extends _i8.PageRouteInfo { SettingsTab({ - _i10.Key? key, + _i9.Key? key, String tab = 'none', String query = 'none', - List<_i9.PageRouteInfo>? children, + List<_i8.PageRouteInfo>? children, }) : super( SettingsTab.name, args: SettingsTabArgs( @@ -283,7 +244,7 @@ class SettingsTab extends _i9.PageRouteInfo { static const String name = 'SettingsTab'; - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { final pathParams = data.inheritedPathParams; @@ -299,7 +260,7 @@ class SettingsTab extends _i9.PageRouteInfo { 'none', ), )); - return _i8.SettingsPage( + return _i7.SettingsPage( key: args.key, tab: args.tab, query: args.query, @@ -315,7 +276,7 @@ class SettingsTabArgs { this.query = 'none', }); - final _i10.Key? key; + final _i9.Key? key; final String tab; @@ -328,9 +289,9 @@ class SettingsTabArgs { } /// generated route for -/// [_i4.WelcomeScreen] -class WelcomeRoute extends _i9.PageRouteInfo { - const WelcomeRoute({List<_i9.PageRouteInfo>? children}) +/// [_i3.WelcomeScreen] +class WelcomeRoute extends _i8.PageRouteInfo { + const WelcomeRoute({List<_i8.PageRouteInfo>? children}) : super( WelcomeRoute.name, initialChildren: children, @@ -338,10 +299,10 @@ class WelcomeRoute extends _i9.PageRouteInfo { static const String name = 'WelcomeRoute'; - static _i9.PageInfo page = _i9.PageInfo( + static _i8.PageInfo page = _i8.PageInfo( name, builder: (data) { - return const _i4.WelcomeScreen(); + return const _i3.WelcomeScreen(); }, ); } diff --git a/auto_route/example/lib/mobile/screens/home_page.dart b/auto_route/example/lib/mobile/screens/home_page.dart index 65f92144..50d95c03 100644 --- a/auto_route/example/lib/mobile/screens/home_page.dart +++ b/auto_route/example/lib/mobile/screens/home_page.dart @@ -1,4 +1,5 @@ import 'package:auto_route/auto_route.dart'; +import 'package:example/mobile/router/router.dart'; import 'package:example/mobile/router/router.gr.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -54,6 +55,7 @@ class HomePageState extends State with TickerProviderStateMixin { @override Widget build(context) { + print('HomePageState.build'); // builder will rebuild everytime this router's stack // updates // we need it to indicate which NavigationRailDestination is active diff --git a/auto_route/example/lib/mobile/screens/profile/my_books_page.dart b/auto_route/example/lib/mobile/screens/profile/my_books_page.dart index 34bcfa72..7a0c91d6 100644 --- a/auto_route/example/lib/mobile/screens/profile/my_books_page.dart +++ b/auto_route/example/lib/mobile/screens/profile/my_books_page.dart @@ -3,7 +3,7 @@ import 'package:example/mobile/router/router.gr.dart'; import 'package:flutter/material.dart'; //ignore_for_file: public_member_api_docs -@RoutePage() +@RoutePage() class MyBooksPage extends StatelessWidget { final String? filter; diff --git a/auto_route/example/lib/mobile/screens/profile/routes.dart b/auto_route/example/lib/mobile/screens/profile/routes.dart index 7935ab1c..8ab7ff66 100644 --- a/auto_route/example/lib/mobile/screens/profile/routes.dart +++ b/auto_route/example/lib/mobile/screens/profile/routes.dart @@ -1,4 +1,5 @@ import 'package:auto_route/auto_route.dart'; +import 'package:example/mobile/router/router.dart'; import 'package:example/mobile/router/router.gr.dart'; //ignore_for_file: public_member_api_docs diff --git a/auto_route/example/lib/mobile/screens/settings_page.dart b/auto_route/example/lib/mobile/screens/settings_page.dart index ed830f7f..05931231 100644 --- a/auto_route/example/lib/mobile/screens/settings_page.dart +++ b/auto_route/example/lib/mobile/screens/settings_page.dart @@ -1,4 +1,5 @@ import 'package:auto_route/auto_route.dart'; +import 'package:example/mobile/router/router.dart'; import 'package:example/mobile/router/router.gr.dart'; import 'package:flutter/material.dart'; diff --git a/auto_route/example/lib/web_demo/router/web_router.dart b/auto_route/example/lib/web_demo/router/web_router.dart index 6e5a2432..651c130a 100644 --- a/auto_route/example/lib/web_demo/router/web_router.dart +++ b/auto_route/example/lib/web_demo/router/web_router.dart @@ -1,13 +1,9 @@ - import 'package:auto_route/auto_route.dart'; import 'package:example/web_demo/router/web_router.gr.dart'; import 'package:example/web_demo/web_main.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; - - - //ignore_for_file: public_member_api_docs @AutoRouterConfig(generateForDir: ['lib/web_demo']) class WebAppRouter extends RootStackRouter { @@ -19,7 +15,8 @@ class WebAppRouter extends RootStackRouter { late final List guards = [ AutoRouteGuard.simple( (resolver, scope) { - if (authService.isAuthenticated || resolver.routeName == WebLoginRoute.name) { + if (authService.isAuthenticated || + resolver.routeName == WebLoginRoute.name) { resolver.next(); } else { resolver.redirect( @@ -32,8 +29,6 @@ class WebAppRouter extends RootStackRouter { ) ]; - - @override List get routes => [ AutoRoute(page: MainWebRoute.page, initial: true), @@ -53,13 +48,15 @@ class WebAppRouter extends RootStackRouter { if (authService.isVerified) { resolver.next(); } else { - resolver.redirect(WebVerifyRoute(onResult: resolver.next)); + resolver + .redirect(WebVerifyRoute(onResult: resolver.next)); } }, ) ], children: [ - AutoRoute(path: 'all', page: UserAllPostsRoute.page, initial: true), + AutoRoute( + path: 'all', page: UserAllPostsRoute.page, initial: true), AutoRoute(path: 'favorite', page: UserFavoritePostsRoute.page), ], ), @@ -103,9 +100,8 @@ class _MainWebPageState extends State { child: ElevatedButton( onPressed: widget.navigate ?? () async { - - final x = await MainWebRoute().push(context); - print(x); + final x = await MainWebRoute().push(context); + print(x); // context.pushRoute( // UserRoute( // id: 2, @@ -130,7 +126,8 @@ class _MainWebPageState extends State { if (kIsWeb) ElevatedButton( onPressed: () { - final currentState = ((context.router.pathState as int?) ?? 0); + final currentState = + ((context.router.pathState as int?) ?? 0); context.router.pushPathState(currentState + 1); }, child: AnimatedBuilder( @@ -312,8 +309,8 @@ class _UserPageState extends State { leading: AutoLeadingButton(), title: Builder( builder: (context) { - return Text( - context.topRouteMatch.name + ' ${widget.id} query: ${widget.query}, fragment: ${widget.fragment}'); + return Text(context.topRouteMatch.name + + ' ${widget.id} query: ${widget.query}, fragment: ${widget.fragment}'); }, ), ), diff --git a/auto_route/example/lib/web_demo/web_main.dart b/auto_route/example/lib/web_demo/web_main.dart index 481dc012..9fdead16 100644 --- a/auto_route/example/lib/web_demo/web_main.dart +++ b/auto_route/example/lib/web_demo/web_main.dart @@ -1,5 +1,4 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:example/web_demo/router/web_router.gr.dart'; +import 'package:example/mobile/router/router.dart'; import 'package:flutter/material.dart'; //ignore_for_file: public_member_api_docs @@ -22,13 +21,7 @@ class AppState extends State { setState(() {}); }); - late final _router = AutoRouterRoot( - routes: [ - AutoRoute(page: MainWebRoute.page,initial: true), - ], - ); - - + late final _router = AppRouter(); @override Widget build(BuildContext context) { return MaterialApp.router( diff --git a/auto_route/lib/auto_route.dart b/auto_route/lib/auto_route.dart index e0beb6fd..0a9c0aee 100644 --- a/auto_route/lib/auto_route.dart +++ b/auto_route/lib/auto_route.dart @@ -1,8 +1,5 @@ library auto_route; -import 'package:flutter/material.dart'; - -export 'src/auto_router_module.dart'; export 'src/common/common.dart'; export 'src/matcher/route_match.dart'; export 'src/navigation_failure.dart'; @@ -26,28 +23,3 @@ export 'src/router/widgets/auto_tabs_router.dart'; export 'src/router/widgets/auto_tabs_scaffold.dart'; export 'src/router/widgets/custom_cupertino_transitions_builder.dart'; export 'src/router/widgets/deferred_widget.dart'; - -extension IterableX on Iterable? { - bool get isNullOrEmpty => this == null || this!.isEmpty; -} - -extension BoolX on bool? { - bool get isTrue => this == true; - - bool get isFalse => this == false; -} - - -extension StringGuardX on String? { - bool get isNullOrEmpty => this == null || this!.isEmpty; - bool get isNullOrBlank => this == null || this!.trim().isEmpty; - - T let(T Function(String str) block, T Function() orElse) => isNullOrEmpty ? orElse() : block(this!); -} - -void worker() { - String? name; - print(name.isNullOrBlank); - Widget nameWidget = name.let(Text.new, SizedBox.new); -} - diff --git a/auto_route/lib/src/auto_router_module.dart b/auto_route/lib/src/auto_router_module.dart deleted file mode 100644 index e08ba730..00000000 --- a/auto_route/lib/src/auto_router_module.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:auto_route/auto_route.dart'; - -/// Module initializers will implement this class -/// to be later used in the root router. -abstract class AutoRouterModule { - /// The map holding the page names and their factories. - Map get pagesMap; -} diff --git a/auto_route/lib/src/common/auto_route_annotations.dart b/auto_route/lib/src/common/auto_route_annotations.dart index 09d281b0..53fe7d56 100644 --- a/auto_route/lib/src/common/auto_route_annotations.dart +++ b/auto_route/lib/src/common/auto_route_annotations.dart @@ -30,41 +30,21 @@ class AutoRouterConfig { /// defaults = const ['lib'] final List generateForDir; - /// Indicates whether the package using the annotation - /// is a module, in that case a different - /// output will be generated. - // ignore: unused_field - final bool _isModule; - - /// A List of modules to be added to the RootRouter. - final List? modules; - /// default constructor const AutoRouterConfig({ this.replaceInRouteName = 'Page|Screen,Route', this.deferredLoading = false, this.generateForDir = const ['lib'], - this.modules, - }) : _isModule = false; - - /// default constructor - const AutoRouterConfig.module({ - this.replaceInRouteName = 'Page|Screen,Route', - this.deferredLoading = false, - this.generateForDir = const ['lib'], - }) : _isModule = true, - modules = null; + }); } /// This annotation is used to mark flutter widgets as routable pages /// by enabling the router to construct them. /// -/// [T] is the results type returned -/// from this page route e.g MaterialPageRoute() /// defaults to dynamic @optionalTypeArgs @Target({TargetKind.classType}) -class RoutePage { +class RoutePage { /// The name of the generated route /// if not provided, a name will be generated from class name /// and maybe altered by [replaceInRouteName] diff --git a/auto_route/lib/src/matcher/route_match.dart b/auto_route/lib/src/matcher/route_match.dart index 9356dbce..c8c1923d 100644 --- a/auto_route/lib/src/matcher/route_match.dart +++ b/auto_route/lib/src/matcher/route_match.dart @@ -89,6 +89,7 @@ class RouteMatch { /// Helper to access [AutoRoute.buildPage] AutoRoutePage buildPage(RouteData data) => _config.buildPage(data); + /// Default constructor const RouteMatch({ required AutoRoute config, diff --git a/auto_route/lib/src/matcher/route_matcher.dart b/auto_route/lib/src/matcher/route_matcher.dart index 563b56c9..0f95f037 100644 --- a/auto_route/lib/src/matcher/route_matcher.dart +++ b/auto_route/lib/src/matcher/route_matcher.dart @@ -60,7 +60,7 @@ class RouteMatcher { match.pathParams.rawMap, ), ).path), - redirectedFrom: config.path, + redirectedFrom: config.path, ); } diff --git a/auto_route/lib/src/route/auto_route_config.dart b/auto_route/lib/src/route/auto_route_config.dart index 010afa66..8c05298f 100644 --- a/auto_route/lib/src/route/auto_route_config.dart +++ b/auto_route/lib/src/route/auto_route_config.dart @@ -4,6 +4,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; import 'package:meta/meta.dart'; +/// A Signature for a function that passes the [RouteData] and returns a [PageRoute] typedef AutoRoutePageBuilder = Widget Function(RouteData data); /// Signature for a function that builds the route title @@ -111,7 +112,9 @@ class AutoRoute { List? children, }) : _path = path, _pageBuilder = page.builder, - _children = children != null && children.isNotEmpty ? RouteCollection.fromList(children) : null; + _children = children != null && children.isNotEmpty + ? RouteCollection.fromList(children) + : null; AutoRoute._change({ required this.page, @@ -261,7 +264,9 @@ class AutoRoute { meta: meta ?? this.meta, maintainState: maintainState ?? this.maintainState, fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog, - children: children != null ? (children.isEmpty ? null : RouteCollection.fromList(children)) : this.children, + children: children != null + ? (children.isEmpty ? null : RouteCollection.fromList(children)) + : this.children, //copy title: title ?? this.title, restorationId: restorationId ?? this.restorationId, @@ -452,7 +457,8 @@ class RouteCollection { /// /// if this [RouteCollection] is created by the router [root] will be true /// else if it's created by a parent route-entry it will be false - factory RouteCollection.fromList(List routes, {bool root = false}) { + factory RouteCollection.fromList(List routes, + {bool root = false}) { final routesMarkedInitial = routes.where((e) => e.initial); throwIf(routesMarkedInitial.length > 1, 'Invalid data\nThere are more than one initial route in this collection\n${routesMarkedInitial.map((e) => e.name)}'); diff --git a/auto_route/lib/src/route/page_info.dart b/auto_route/lib/src/route/page_info.dart index c59b1c91..1f59c2d8 100644 --- a/auto_route/lib/src/route/page_info.dart +++ b/auto_route/lib/src/route/page_info.dart @@ -14,11 +14,13 @@ class PageInfo { /// Default constructor const PageInfo(this.name, {required this.builder}); - @override bool operator ==(Object other) => identical(this, other) || - other is PageInfo && runtimeType == other.runtimeType && builder == other.builder && name == other.name; + other is PageInfo && + runtimeType == other.runtimeType && + builder == other.builder && + name == other.name; @override int get hashCode => name.hashCode ^ builder.hashCode; @@ -28,7 +30,6 @@ class PageInfo { /// Dummy [PageInfo] used to represent the root route static final root = _NoBuilderPageInfo('#Root'); - } /// Dummy [PageInfo] used to represent a redirect route diff --git a/auto_route/lib/src/route/page_route_info.dart b/auto_route/lib/src/route/page_route_info.dart index d43fb6a3..54e77da6 100644 --- a/auto_route/lib/src/route/page_route_info.dart +++ b/auto_route/lib/src/route/page_route_info.dart @@ -194,3 +194,23 @@ class PageRouteInfo { const MapEquality().hash(rawQueryParams) ^ const ListEquality().hash(initialChildren); } + + +/// A proxy Route page that provides a way to create a [PageRouteInfo] +/// without the need for creating a new Page Widget +class EmptyShellRoute { + + /// Page name + final String name; + + /// Default constructor + EmptyShellRoute(this.name); + + /// creates [PageInfo] with an just an [AutoRouter] widget + late final page = PageInfo(name, builder: (_) => const AutoRouter()); + + /// Creates a new instance with of [PageRouteInfo] + PageRouteInfo call({List? children}) { + return PageRouteInfo(name, initialChildren: children); + } +} diff --git a/auto_route/lib/src/route/route_data.dart b/auto_route/lib/src/route/route_data.dart index a092f338..c7edc270 100644 --- a/auto_route/lib/src/route/route_data.dart +++ b/auto_route/lib/src/route/route_data.dart @@ -188,6 +188,6 @@ class RouteData { /// Builds the [AutoRoutePage] page AutoRoutePage buildPage() { - return _match.buildPage(this); + return _match.buildPage(this); } } diff --git a/auto_route/lib/src/router/auto_router_x.dart b/auto_route/lib/src/router/auto_router_x.dart index 521fd218..50bed511 100644 --- a/auto_route/lib/src/router/auto_router_x.dart +++ b/auto_route/lib/src/router/auto_router_x.dart @@ -26,12 +26,6 @@ extension AutoRouterX on BuildContext { }) => router.replace(route, onFailure: onFailure); - /// see [StackRouter.maybePop] - @optionalTypeArgs - @Deprecated('Renamed to maybePop to avoid confusion') - Future popRoute([T? result]) => - router.maybePop(result); - /// see [StackRouter.maybePop] @optionalTypeArgs Future maybePop([T? result]) => diff --git a/auto_route/lib/src/router/controller/auto_router_delegate.dart b/auto_route/lib/src/router/controller/auto_router_delegate.dart index bbd6fc22..742a4e3f 100644 --- a/auto_route/lib/src/router/controller/auto_router_delegate.dart +++ b/auto_route/lib/src/router/controller/auto_router_delegate.dart @@ -94,20 +94,6 @@ class AutoRouterDelegate extends RouterDelegate with ChangeNotifier { reevaluateListenable?.addListener(controller.reevaluateGuards); } - /// Builds a [_DeclarativeAutoRouterDelegate] which uses - /// a declarative list of routes to update navigator stack - @Deprecated( - 'Declarative Root routing is not longer supported, Use route guards to conditionally navigate') - factory AutoRouterDelegate.declarative( - RootStackRouter controller, { - required RoutesBuilder routes, - String? navRestorationScopeId, - RoutePopCallBack? onPopRoute, - OnNavigateCallBack? onNavigate, - NavigatorObserversBuilder navigatorObservers, - DeepLinkBuilder? deepLinkBuilder, - }) = _DeclarativeAutoRouterDelegate; - /// Helper to access current urlState UrlState get urlState => controller.navigationHistory.urlState; @@ -274,94 +260,6 @@ class _AutoRootRouterState extends State<_AutoRootRouter> { } } -class _DeclarativeAutoRouterDelegate extends AutoRouterDelegate { - final RoutesBuilder routes; - final RoutePopCallBack? onPopRoute; - final OnNavigateCallBack? onNavigate; - - _DeclarativeAutoRouterDelegate( - RootStackRouter router, { - required this.routes, - String? navRestorationScopeId, - super.deepLinkBuilder, - this.onPopRoute, - this.onNavigate, - NavigatorObserversBuilder navigatorObservers = - AutoRouterDelegate.defaultNavigatorObserversBuilder, - }) : super( - router, - navRestorationScopeId: navRestorationScopeId, - navigatorObservers: navigatorObservers, - ) { - router._managedByWidget = true; - } - - @override - Future setInitialRoutePath(UrlState configuration) async { - final platformDeepLink = PlatformDeepLink._(configuration, true); - if (deepLinkBuilder != null) { - final deepLink = await deepLinkBuilder!(platformDeepLink); - _handleDeclarativeDeepLink(deepLink); - } else if (configuration.hasSegments) { - _handleDeclarativeDeepLink(platformDeepLink); - } - return SynchronousFuture(null); - } - - void _handleDeclarativeDeepLink(DeepLink deepLink) { - if (deepLink is _IgnoredDeepLink) return; - throwIf(!deepLink.isValid, 'Can not resolve initial route'); - List? routes; - if (deepLink is PlatformDeepLink) { - routes = deepLink.matches.map((e) => e.toPageRouteInfo()).toList(); - } else if (deepLink is _PathDeepLink) { - routes = controller.buildPageRoutesStack(deepLink.path); - } else if (deepLink is _RoutesDeepLink) { - routes = deepLink.routes; - } - controller.pendingRoutesHandler._setPendingRoutes(routes); - } - - @override - Future setNewRoutePath(UrlState tree) async { - return _onNavigate(tree); - } - - Future _onNavigate(UrlState tree) { - if (tree.hasSegments) { - controller.navigateAll(tree.segments); - } - if (onNavigate != null) { - onNavigate!(tree); - } - - return SynchronousFuture(null); - } - - @override - Widget build(BuildContext context) { - final stateHash = controller.stateHash; - return RouterScope( - controller: controller, - inheritableObserversBuilder: navigatorObservers, - stateHash: stateHash, - navigatorObservers: _navigatorObservers, - child: StackRouterScope( - controller: controller, - stateHash: stateHash, - child: AutoRouteNavigator( - router: controller, - key: GlobalObjectKey(controller.hashCode), - declarativeRoutesBuilder: routes, - navRestorationScopeId: navRestorationScopeId, - navigatorObservers: _navigatorObservers, - didPop: onPopRoute, - ), - ), - ); - } -} - /// Holds deep-link information abstract class DeepLink { const DeepLink._(); diff --git a/auto_route/lib/src/router/controller/root_stack_router.dart b/auto_route/lib/src/router/controller/root_stack_router.dart index 038e7684..0cf9d768 100644 --- a/auto_route/lib/src/router/controller/root_stack_router.dart +++ b/auto_route/lib/src/router/controller/root_stack_router.dart @@ -3,10 +3,6 @@ part of 'routing_controller.dart'; /// Signature for a function uses [pagesMap] to build an [AutoRoutePage] typedef PageBuilder = AutoRoutePage Function(RouteData data); -/// Signature for a function that builds an [AutoRoutePage] -/// Used by [RoutingController] -typedef PageFactory = Page Function(RouteData data); - /// An Implementation of [StackRouter] used by [AutoRouterDelegate] abstract class RootStackRouter extends StackRouter { /// Default constructor @@ -21,7 +17,8 @@ abstract class RootStackRouter extends StackRouter { DeepLinkBuilder? deepLinkBuilder, String? navRestorationScopeId, WidgetBuilder? placeholder, - NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, + NavigatorObserversBuilder navigatorObservers = + AutoRouterDelegate.defaultNavigatorObserversBuilder, bool includePrefixMatches = !kIsWeb, bool Function(String? location)? neglectWhen, bool rebuildStackOnDeepLink = false, @@ -61,7 +58,6 @@ abstract class RootStackRouter extends StackRouter { pendingChildren: const [], ); - /// The list of route entries to match against List get routes; @@ -91,36 +87,15 @@ abstract class RootStackRouter extends StackRouter { ); } - AutoRouterDelegate? _lazyRootDelegate; - /// Builds a lazy instance of [AutoRouterDelegate.declarative] - @Deprecated('Declarative Root routing is not longer supported, Use route guards to conditionally navigate') - AutoRouterDelegate declarativeDelegate({ - required RoutesBuilder routes, - String? navRestorationScopeId, - RoutePopCallBack? onPopRoute, - OnNavigateCallBack? onNavigate, - DeepLinkBuilder? deepLinkBuilder, - NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, - }) { - return _lazyRootDelegate ??= AutoRouterDelegate.declarative( - this, - routes: routes, - onNavigate: onNavigate, - onPopRoute: onPopRoute, - navRestorationScopeId: navRestorationScopeId, - navigatorObservers: navigatorObservers, - deepLinkBuilder: deepLinkBuilder, - ); - } - /// Builds a lazy instance of [AutoRouterDelegate] /// _lazyRootDelegate is only built one time AutoRouterDelegate delegate({ String? navRestorationScopeId, WidgetBuilder? placeholder, - NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, + NavigatorObserversBuilder navigatorObservers = + AutoRouterDelegate.defaultNavigatorObserversBuilder, DeepLinkBuilder? deepLinkBuilder, bool rebuildStackOnDeepLink = false, Listenable? reevaluateListenable, @@ -159,27 +134,6 @@ abstract class RootStackRouter extends StackRouter { NavigationHistory get navigationHistory => _navigationHistory; @override - late final RouteCollection routeCollection = RouteCollection.fromList(routes, root: true); + late final RouteCollection routeCollection = + RouteCollection.fromList(routes, root: true); } - - -/// A declarative implementation of [RootStackRouter] -class AutoRouterRoot extends RootStackRouter { - @override - final List routes; - - @override - final List guards; - - @override - final RouteType defaultRouteType; - - /// Default constructor - AutoRouterRoot({ - required this.routes, - this.guards = const [], - this.defaultRouteType = const RouteType.material(), - super.navigatorKey, - }); - -} \ No newline at end of file diff --git a/auto_route/lib/src/router/controller/routing_controller.dart b/auto_route/lib/src/router/controller/routing_controller.dart index 8ec3d9ed..fdc65a2b 100644 --- a/auto_route/lib/src/router/controller/routing_controller.dart +++ b/auto_route/lib/src/router/controller/routing_controller.dart @@ -13,8 +13,11 @@ import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; part '../../route/route_data.dart'; + part 'auto_route_guard.dart'; + part 'auto_router_delegate.dart'; + part 'root_stack_router.dart'; // ignore_for_file: deprecated_member_use_from_same_package @@ -501,7 +504,6 @@ abstract class RoutingController with ChangeNotifier { ); } - /// Clients can either pop their own [_pages] stack /// or defer the call to a parent controller /// @@ -509,20 +511,6 @@ abstract class RoutingController with ChangeNotifier { @optionalTypeArgs Future maybePop([T? result]); - /// Clients can either pop their own [_pages] stack - /// or defer the call to a parent controller - /// - /// see [Navigator.maybePop(context)] for more details - @optionalTypeArgs - @Deprecated( - 'pop was renamed to maybePop to avoid confusion, if you are looking for the implementation of Navigator.pop user popForced') - Future pop([T? result]) => maybePop(result); - - /// Calls [maybePop] on the controller with the top-most visible page - @optionalTypeArgs - @Deprecated('pop was renamed to maybePopTop') - Future popTop([T? result]) => maybePopTop(result); - /// Calls [maybePop] on the controller with the top-most visible page @optionalTypeArgs Future maybePopTop([T? result]) => @@ -781,7 +769,7 @@ class TabsRouter extends RoutingController { for (var route in routes) { var data = _createRouteData(route, routeData); try { - _pages.add(data.buildPage()) ; + _pages.add(data.buildPage()); } on MissingRequiredParameterError catch (e) { if (fromDefault) { throw FlutterError( @@ -796,8 +784,6 @@ class TabsRouter extends RoutingController { } } - - @override List? _composeMatchesForReevaluate() { final matches = []; @@ -1034,7 +1020,6 @@ abstract class StackRouter extends RoutingController { @override RouteCollection get routeCollection; - @override RouteMatcher get matcher; @@ -1606,16 +1591,14 @@ abstract class StackRouter extends RoutingController { return page.popped; } - Future _canNavigate( RouteMatch route, { OnNavigationFailure? onFailure, List pendingRoutes = const [], bool isReevaluating = false, }) async { - final guards = [ - ...root.guards, + ...root.guards, ...route.guards, ]; if (guards.isEmpty) { diff --git a/auto_route/lib/src/router/widgets/auto_router.dart b/auto_route/lib/src/router/widgets/auto_router.dart index fe7fd2ec..3403b718 100644 --- a/auto_route/lib/src/router/widgets/auto_router.dart +++ b/auto_route/lib/src/router/widgets/auto_router.dart @@ -35,7 +35,8 @@ class AutoRouter extends StatefulWidget { /// Default constructor const AutoRouter({ super.key, - this.navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, + this.navigatorObservers = + AutoRouterDelegate.defaultNavigatorObserversBuilder, this.builder, this.navRestorationScopeId, this.navigatorKey, @@ -47,7 +48,8 @@ class AutoRouter extends StatefulWidget { /// a declarative list of routes to update navigator stack static Widget declarative({ Key? key, - NavigatorObserversBuilder navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, + NavigatorObserversBuilder navigatorObservers = + AutoRouterDelegate.defaultNavigatorObserversBuilder, required RoutesBuilder routes, RoutePopCallBack? onPopRoute, String? navRestorationScopeId, @@ -80,7 +82,8 @@ class AutoRouter extends StatefulWidget { var scope = StackRouterScope.of(context, watch: watch); assert(() { if (scope == null) { - throw FlutterError('AutoRouter operation requested with a context that does not include an AutoRouter.\n' + throw FlutterError( + 'AutoRouter operation requested with a context that does not include an AutoRouter.\n' 'The context used to retrieve the Router must be that of a widget that ' 'is a descendant of an AutoRouter widget.'); } @@ -193,7 +196,8 @@ class _DeclarativeAutoRouter extends StatefulWidget { const _DeclarativeAutoRouter({ required this.routes, - this.navigatorObservers = AutoRouterDelegate.defaultNavigatorObserversBuilder, + this.navigatorObservers = + AutoRouterDelegate.defaultNavigatorObserversBuilder, this.onPopRoute, this.navigatorKey, this.navRestorationScopeId, diff --git a/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart b/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart index 87a3b954..b5461f3f 100644 --- a/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart +++ b/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart @@ -51,63 +51,6 @@ final Animatable _kBottomUpTween = Tween( end: Offset.zero, ); -/// A modal route that replaces the entire screen with an iOS transition. -/// -/// {@macro flutter.cupertino.cupertinoRouteTransitionMixin} -/// -/// By default, when a modal route is replaced by another, the previous route -/// remains in memory. To free all the resources when this is not necessary, set -/// [maintainState] to false. -/// -/// The type `T` specifies the return type of the route which can be supplied as -/// the route is popped from the stack via [Navigator.pop] when an optional -/// `result` can be provided. -/// -/// See also: -/// -/// * [CustomCupertinoRouteTransitionMixin], for a mixin that provides iOS transition -/// for this modal route. -/// * [MaterialPageRoute], for an adaptive [PageRoute] that uses a -/// platform-appropriate transition. -/// * [CupertinoPageScaffold], for applications that have one page with a fixed -/// navigation bar on top. -/// * [CupertinoTabScaffold], for applications that have a tab bar at the -/// bottom with multiple pages. -/// * [CupertinoPage], for a [Page] version of this class. -class CupertinoPageRoute extends PageRoute - with - CupertinoRouteTransitionMixin, - CupertinoRouteTransitionOverrideMixin { - /// Creates a page route for use in an iOS designed app. - /// - /// The [builder], [maintainState], and [fullscreenDialog] arguments must not - /// be null. - CupertinoPageRoute({ - required this.builder, - this.title, - super.settings, - this.maintainState = true, - super.fullscreenDialog, - }) { - assert(opaque); - } - - /// Builds the primary contents of the route. - final WidgetBuilder builder; - - @override - Widget buildContent(BuildContext context) => builder(context); - - @override - final String? title; - - @override - final bool maintainState; - - @override - String get debugLabel => '${super.debugLabel}(${settings.name})'; -} - /// A mixin that implements methods and/or parameters of a [PageRoute]. /// /// Meant to be used as an override of methods/parameters implemented in @@ -541,30 +484,32 @@ class _CupertinoEdgeShadowDecoration extends Decoration { double t, ) { if (a == null && b == null) return null; + final aColors = a?._colors; + final bColors = b?._colors; if (a == null) { - return b!._colors == null + return bColors == null ? b - : _CupertinoEdgeShadowDecoration._(b._colors! + : _CupertinoEdgeShadowDecoration._(bColors .map((Color color) => Color.lerp(null, color, t)!) .toList()); } if (b == null) { - return a._colors == null + return aColors == null ? a - : _CupertinoEdgeShadowDecoration._(a._colors! + : _CupertinoEdgeShadowDecoration._(aColors .map((Color color) => Color.lerp(null, color, 1.0 - t)!) .toList()); } - assert(b._colors != null || a._colors != null); + assert(bColors != null || aColors != null); // If it ever becomes necessary, we could allow decorations with different // length' here, similarly to how it is handled in [LinearGradient.lerp]. - assert(b._colors == null || - a._colors == null || - a._colors!.length == b._colors!.length); + assert(bColors == null || + aColors == null || + aColors.length == bColors.length); return _CupertinoEdgeShadowDecoration._( [ - for (int i = 0; i < b._colors!.length; i += 1) - Color.lerp(a._colors?[i], b._colors?[i], t)!, + for (int i = 0; i < bColors!.length; i += 1) + Color.lerp(a._colors?[i], bColors[i], t)!, ], ); } @@ -679,34 +624,3 @@ class _CupertinoEdgeShadowPainter extends BoxPainter { } } } - -/// A custom cupertino transition builder to fix unwanted shadows in nested navigator -/// -/// This fixes the issue referenced here -/// https://stackoverflow.com/questions/53457772/why-there-is-a-shadow-between-nested-navigator -/// https://stackoverflow.com/questions/68986632/rid-of-elevation-of-nested-flutter-navigator-2-0 -@Deprecated( - 'The issue, this builder fixes, was already fixed in the freamework in v3.0.0' - '(https://github.com/flutter/flutter/pull/95537, ' - 'https://docs.flutter.dev/release/release-notes/release-notes-3.0.0) ' - 'so there is no more reason to use this builder. ' - 'Will be deleted in the next major release. ' - 'If you still need this builder for other reasons, ' - 'use CupertinoPageTransitionsBuilder instead. as it is completely identic', -) -class NoShadowCupertinoPageTransitionsBuilder extends PageTransitionsBuilder { - /// Constructs a page transition animation that matches the iOS transition. - const NoShadowCupertinoPageTransitionsBuilder(); - - @override - Widget buildTransitions( - PageRoute route, - BuildContext context, - Animation animation, - Animation secondaryAnimation, - Widget child, - ) { - return CupertinoRouteTransitionMixin.buildPageTransitions( - route, context, animation, secondaryAnimation, child); - } -} diff --git a/auto_route/test/parameters_test.dart b/auto_route/test/parameters_test.dart index 785c4377..76c01621 100644 --- a/auto_route/test/parameters_test.dart +++ b/auto_route/test/parameters_test.dart @@ -126,9 +126,10 @@ void main() { expect(params.getBool('key2'), false); }); - test('Calling Parameters.getList on a list value should return a ', - () { - const params = Parameters({'key': ['1', '2']}); + test('Calling Parameters.getList on a list value should return a ', () { + const params = Parameters({ + 'key': ['1', '2'] + }); expect(params.getList('key'), isA()); expect(params.optList('key2'), null); }); diff --git a/auto_route_generator/lib/src/builders/auto_router_builder_base.dart b/auto_route_generator/lib/src/builders/auto_router_builder_base.dart index 0d4d504f..efb54cda 100644 --- a/auto_route_generator/lib/src/builders/auto_router_builder_base.dart +++ b/auto_route_generator/lib/src/builders/auto_router_builder_base.dart @@ -16,7 +16,6 @@ import 'package:source_gen/source_gen.dart'; import '../../utils.dart'; import '../resolvers/router_config_resolver.dart'; -import '../resolvers/type_resolver.dart'; const _typeChecker = TypeChecker.fromRuntime(AutoRouterConfig); @@ -119,9 +118,7 @@ abstract class AutoRouterBuilderBase extends CacheAwareBuilder { final usesPartBuilder = _hasPartDirective(clazz); - final router = RouterConfigResolver( - TypeResolver(await buildStep.resolver.libraries.toList()), - ).resolve( + final router = RouterConfigResolver().resolve( annotation, buildStep.inputId, clazz, diff --git a/auto_route_generator/lib/src/models/route_config.dart b/auto_route_generator/lib/src/models/route_config.dart index a4c3c748..2c433b3b 100644 --- a/auto_route_generator/lib/src/models/route_config.dart +++ b/auto_route_generator/lib/src/models/route_config.dart @@ -17,8 +17,6 @@ class RouteConfig { /// the class name of the route final String className; - /// the return type of the route - final ResolvedType? returnType; /// the parameters of the route final List parameters; @@ -40,7 +38,6 @@ class RouteConfig { required this.className, this.parameters = const [], this.hasWrappedRoute, - this.returnType, this.hasConstConstructor = false, this.deferredLoading, }); @@ -96,7 +93,6 @@ class RouteConfig { bool? fullMatch, ResolvedType? pageType, String? className, - ResolvedType? returnType, List? parameters, String? redirectTo, bool? hasWrappedRoute, @@ -109,7 +105,6 @@ class RouteConfig { pathParams: pathParams ?? this.pathParams, pageType: pageType ?? this.pageType, className: className ?? this.className, - returnType: returnType ?? this.returnType, parameters: parameters ?? this.parameters, hasWrappedRoute: hasWrappedRoute ?? this.hasWrappedRoute, hasConstConstructor: hasConstConstructor ?? this.hasConstConstructor, @@ -124,7 +119,6 @@ class RouteConfig { 'pathParams': this.pathParams.map((e) => e.toJson()).toList(), 'pageType': this.pageType?.toJson(), 'className': this.className, - 'returnType': this.returnType?.toJson(), 'parameters': this.parameters.map((e) => e.toJson()).toList(), 'hasWrappedRoute': this.hasWrappedRoute, 'hasConstConstructor': this.hasConstConstructor, @@ -153,7 +147,6 @@ class RouteConfig { pathParams: pathParams, pageType: map['pageType'] == null ? null : ResolvedType.fromJson(map['pageType']), className: map['className'] as String, - returnType: map['returnType'] == null ? null : ResolvedType.fromJson(map['returnType']), parameters: parameters, hasWrappedRoute: map['hasWrappedRoute'] as bool?, hasConstConstructor: map['hasConstConstructor'] as bool, diff --git a/auto_route_generator/lib/src/models/router_config.dart b/auto_route_generator/lib/src/models/router_config.dart index 8e8240df..701435e2 100644 --- a/auto_route_generator/lib/src/models/router_config.dart +++ b/auto_route_generator/lib/src/models/router_config.dart @@ -1,4 +1,4 @@ -import 'resolved_type.dart'; + /// RouterConfig class RouterConfig { @@ -23,11 +23,6 @@ class RouterConfig { /// The list of directories to generate for final List generateForDir; - /// Whether the router is a module - final bool isModule; - - /// The list of modules - final List modules; /// Default constructor const RouterConfig({ @@ -38,8 +33,6 @@ class RouterConfig { required this.path, required this.cacheHash, required this.generateForDir, - this.isModule = false, - this.modules = const [], }); /// Serializes this instance to a map @@ -52,8 +45,6 @@ class RouterConfig { 'path': this.path, 'cacheHash': this.cacheHash, 'generateForDir': this.generateForDir, - 'isModule': this.isModule, - 'modules': this.modules, }; } @@ -67,10 +58,6 @@ class RouterConfig { path: map['path'] as String, cacheHash: map['cacheHash'] as int?, generateForDir: (map['generateForDir'] as List).cast(), - isModule: map['isModule'] as bool, - modules: (map['modules'] as List) - .map((e) => ResolvedType.fromJson(e)) - .toList(), ); } } diff --git a/auto_route_generator/lib/src/resolvers/route_config_resolver.dart b/auto_route_generator/lib/src/resolvers/route_config_resolver.dart index 54382abb..8eaa892a 100644 --- a/auto_route_generator/lib/src/resolvers/route_config_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/route_config_resolver.dart @@ -1,9 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/type.dart'; import 'package:source_gen/source_gen.dart'; import '../../utils.dart'; -import '../models/resolved_type.dart'; import '../models/route_config.dart'; import '../models/route_parameter_config.dart'; import '../resolvers/route_parameter_resolver.dart'; @@ -32,12 +30,6 @@ class RouteConfigResolver { var pageType = _typeResolver.resolveType(page); var className = page.getDisplayString(withNullability: false); - var returnType = ResolvedType(name: 'dynamic'); - var dartType = routePage.objectValue.type; - if (dartType is InterfaceType) { - returnType = _typeResolver.resolveType(dartType.typeArguments.first); - } - var name = routePage.peek('name')?.stringValue; final constructor = classElement.unnamedConstructor; throwIf( @@ -93,7 +85,6 @@ class RouteConfigResolver { hasWrappedRoute: hasWrappedRoute, parameters: parameters, hasConstConstructor: hasConstConstructor, - returnType: returnType, pageType: pageType, deferredLoading: isDeferred, ); diff --git a/auto_route_generator/lib/src/resolvers/router_config_resolver.dart b/auto_route_generator/lib/src/resolvers/router_config_resolver.dart index 4680d030..02c07fee 100644 --- a/auto_route_generator/lib/src/resolvers/router_config_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/router_config_resolver.dart @@ -3,14 +3,12 @@ import 'package:build/build.dart'; import 'package:source_gen/source_gen.dart'; import '../models/router_config.dart'; -import '../resolvers/type_resolver.dart'; /// Extracts and holds router configs class RouterConfigResolver { - final TypeResolver _typeResolver; /// Default constructor - RouterConfigResolver(this._typeResolver); + RouterConfigResolver(); /// Resolves a [ClassElement] into a consumable [RouterConfig] RouterConfig resolve( @@ -20,13 +18,6 @@ class RouterConfigResolver { bool usesPartBuilder = false, int? cacheHash, }) { - // /// ensure router config classes are prefixed with $ - // /// to use the stripped name for the generated class - // throwIf( - // !usesPartBuilder && !clazz.displayName.startsWith(r'$'), - // 'Router class name must be prefixed with \$', - // element: clazz, - // ); final deferredLoading = autoRouter.peek('deferredLoading')?.boolValue ?? false; @@ -35,11 +26,6 @@ class RouterConfigResolver { .read('generateForDir') .listValue .map((e) => e.toStringValue()!); - var isModule = autoRouter.read('_isModule').boolValue; - final modules = autoRouter - .peek('modules') - ?.listValue - .map((e) => _typeResolver.resolveType(e.toTypeValue()!)); return RouterConfig( routerClassName: clazz.displayName, @@ -49,8 +35,6 @@ class RouterConfigResolver { path: input.path, cacheHash: cacheHash, generateForDir: List.of(generateForDir), - isModule: isModule, - modules: List.of(modules ?? []), ); } } From 2b62ceaf0cb15e359f90f40f1c91e6e6c052433f Mon Sep 17 00:00:00 2001 From: milad Date: Sun, 28 Jul 2024 21:31:38 +0300 Subject: [PATCH 03/13] Add proxy to build empty router shells remove deprecated code remove module implementation as there is no need for it any more --- .../example/lib/mobile/screens/home_page.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/auto_route/example/lib/mobile/screens/home_page.dart b/auto_route/example/lib/mobile/screens/home_page.dart index 50d95c03..67e41561 100644 --- a/auto_route/example/lib/mobile/screens/home_page.dart +++ b/auto_route/example/lib/mobile/screens/home_page.dart @@ -55,7 +55,6 @@ class HomePageState extends State with TickerProviderStateMixin { @override Widget build(context) { - print('HomePageState.build'); // builder will rebuild everytime this router's stack // updates // we need it to indicate which NavigationRailDestination is active @@ -67,19 +66,20 @@ class HomePageState extends State with TickerProviderStateMixin { (d) => context.router.isRouteActive(d.route.routeName), ); // there might be no active route until router is mounted - // so we play safe + // so we play it safe if (activeIndex == -1) { activeIndex = 0; } return Row( children: [ NavigationRail( - destinations: destinations - .map((item) => NavigationRailDestination( - icon: Icon(item.icon), - label: Text(item.label), - )) - .toList(), + destinations: [ + for (final d in destinations) + NavigationRailDestination( + icon: Icon(d.icon), + label: Text(d.label), + ) + ], selectedIndex: activeIndex, onDestinationSelected: (index) { // use navigate instead of push so you won't have From 660e90d818d789c02b374accc3c0c3a91159f7f8 Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 13:38:53 +0300 Subject: [PATCH 04/13] update migration docs --- README.md | 217 ++--- migrations/migrating_to_v6.md | 91 ++ migrations/migrating_to_v9.md | 120 +++ old/pre_v9_README.md | 1622 +++++++++++++++++++++++++++++++++ 4 files changed, 1890 insertions(+), 160 deletions(-) create mode 100644 migrations/migrating_to_v6.md create mode 100644 migrations/migrating_to_v9.md create mode 100644 old/pre_v9_README.md diff --git a/README.md b/README.md index 78e1c7cc..06a745e8 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,13 @@ - [ActiveGuardObserver](#activeguardobserver) - [Examples](#examples) -**Note:** [AutoRoute-Helper] is no longer supported. ## Migration guides +- [Migrating to v9](https://github.com/Milad-Akarie/auto_route_library/blob/master/migrations/migrating_to_v9.md) +- [Migrating to v6](https://github.com/Milad-Akarie/auto_route_library/blob/master/migrations/migrating_to_v6.md) -- [Migrating to v6](#migrating-to-v6) - -## Pre v6 documentation - +## Old documentation +- [Pre v9 documentation](https://github.com/Milad-Akarie/auto_route_library/blob/master/old/pre_v9_README.md) - [Pre v6 documentation](https://github.com/Milad-Akarie/auto_route_library/blob/master/old/pre_v6_README.md) ## Introduction @@ -90,12 +89,12 @@ dev_dependencies: ## Setup And Usage -1. Create a router class and annotate it with `@AutoRouterConfig` then extend "$YourClassName" +1. Create a router class and annotate it with `@AutoRouterConfig` then extend "RootStackRouter" from The auto_route package 2. Override the routes getter and start adding your routes. ```dart @AutoRouterConfig() -class AppRouter extends $AppRouter { +class AppRouter extends RootStackRouter { @override List get routes => [ @@ -106,20 +105,9 @@ class AppRouter extends $AppRouter { ### Using part builder -To generate a part-of file simply add a `part` directive to your `AppRouter` and extend the generated private router. **Note:** The `deferredLoading` functionality does not work with part-file setup. +To generate a part-of file simply add a `part` directive to your `AppRouter`. -```dart -part 'app_router.gr.dart'; - -@AutoRouterConfig() -class AppRouter extends _$AppRouter { - - @override - List get routes => [ - /// routes go here - ]; -} -``` +**Note:** The `deferredLoading` functionality does not work with part-file setup. ### Generating Routable pages @@ -147,15 +135,23 @@ dart run build_runner build #### Add the generated route to your routes list ```dart -@AutoRouterConfig(replaceInRouteName: 'Screen,Route') -class AppRouter extends $AppRouter { +@AutoRouterConfig(replaceInRouteName: 'Screen|Page,Route') +class AppRouter extends RootStackRouter { + @override + RouteType get defaultRouteType => RouteType.material(); //.cupertino, .adaptive ..etc + @override List get routes => [ // HomeScreen is generated as HomeRoute because // of the replaceInRouteName property AutoRoute(page: HomeRoute.page), ]; + + @override + List get guards => [ + // optionally add root guards here + ]; } ``` @@ -187,10 +183,10 @@ A `PageRouteInfo` object will be generated for every declared **AutoRoute**. The class BookListRoute extends PageRouteInfo { const BookListRoute({ List? children, - }) : super(name, path: '/books', initialChildren: children); + }) : super(name, initialChildren: children); static const String name = 'BookListRoute'; - static const PageInfo page = PageInfo(name); + static const PageInfo page = PageInfo(name,builder: (...)); } ``` @@ -302,17 +298,7 @@ then inside of your `LoginPage`, pop with results ```dart router.maybePop(true); ``` - -as you'd notice we did not specify the result type, we're playing with dynamic values here, which can be risky and I personally don't recommend it. - -To avoid working with dynamic values, we specify what type of results we expect our page to return, which is a `bool` value. - -```dart -@RoutePage() -class LoginPage extends StatelessWidget {} -``` - -we push and specify the type of results we're expecting +Specifying the type of the result is optional, but it's recommended to avoid runtime errors. ```dart var result = await router.push(LoginRoute()); @@ -371,7 +357,7 @@ Defining nested routes is as easy as populating the children field of the parent ```dart @AutoRouterConfig(replaceInRouteName: 'Page,Route') -class AppRouter extends $AppRouter { +class AppRouter extends RootStackRouter { @override List get routes => [ @@ -407,7 +393,7 @@ class DashboardPage extends StatelessWidget { ), Expanded( // nested routes will be rendered here - child: AutoRouter(), + child: AutoRouter(), // this is important ), ], ); @@ -1053,26 +1039,31 @@ AutoRoute( #### Guarding all stack-routes -You can have all your stack-routes (non-tab-routes) go through a global guard by having your router implement an AutoRouteGuard. Lets say you have an app with no publish screens, we'd have a global guard that only allows navigation if the user is authenticated or if we're navigating to the LoginRoute. +You can have all your stack-routes (non-tab-routes) go through a list of global guards by overriding the guards property inside your router class. Lets say you have an app with no public screens, we'd have a global guard that only allows navigation if the user is authenticated or if we're navigating to the LoginRoute. ```dart @AutoRouterConfig() -class AppRouter extends $AppRouter implements AutoRouteGuard { +class AppRouter extends RootStackRouter{ @override - void onNavigation(NavigationResolver resolver, StackRouter router) { - if(isAuthenticated || resolver.route.name == LoginRoute.name) { - // we continue navigation - resolver.next(); - } else { - // else we navigate to the Login page so we get authenticated + late final List guards = [ + AutoRouteGuard.simple((resolver, router) { + if(isAuthenticated || resolver.routeName == LoginRoute.name) { + // we continue navigation + resolver.next(); + } else { + // else we navigate to the Login page so we get authenticated + + // tip: use resolver.redirect to have the redirected route + // automatically removed from the stack when the resolver is completed + resolver.redirect(LoginRoute(onResult: (didLogin) => resolver.next(didLogin))); + } + }, + ), + // add more guards here + ]; - // tip: use resolver.redirect to have the redirected route - // automatically removed from the stack when the resolver is completed - resolver.redirect(LoginRoute(onResult: (didLogin) => resolver.next(didLogin))); - } - } - // ..routes[] +// ..routes[] } ``` @@ -1359,31 +1350,29 @@ CustomRoute( ### Including Micro/External Packages -To include routes inside of a depended-on package, that package needs to generate an `AutoRouterModule` that will be later consumed by the root router. - -To have a package output an `AutoRouterModule` instead of a `RootStackRouter`, we need to use the `AutoRouterConfig.module()` annotation like follows +To include routes inside of a depended-on package, we generated the routes inside the micro package like normal, then either use the generated routes inside your main router individually, +or declare them inside your micro router and merge them with the main router. ```dart -@AutoRouterConfig.module() -class MyPackageModule extends $MyPackageModule {} -``` + final myMicroRouter = MyMicroRouter(); -Then when setting up our root router we need to tell it to include the generated module. - -```dart -@AutoRouterConfig(modules: [MyPackageModule]) -class AppRouter extends $AppRouter {} + @override + List get routes => [ + AutoRoute(page: HomeRoute.page, initial: true), + /// use micro routes individually + AutoRoute(page: RouteFromMicroPackage.page), + /// or merge all routes from micro router + ...myMicroRouter.routes, + ]; ``` -Now you can use `PageRouteInfos` generated inside `MyPackageModule`. - -`Tip:` You can add export `MyPackageModule` to `app_router.dart`, so you only import `app_router.dart` inside of your code. +`Tip:` You can add export `MyMicroRouter` to `app_router.dart`, so you only import `app_router.dart` inside of your code. ```dart // ...imports -export 'package:my_package/my_package_module.dart' -@AutoRouterConfig(modules: [MyPackageModule]) -class AppRouter extends $AppRouter {} +export 'package:my_package/my_micro_router.dart' +@AutoRouterConfig() +class AppRouter extends RootStackRouter {} ``` ## Configuring builders @@ -1519,98 +1508,6 @@ void initState(){ ``` -## Migrating to v6 - -In version 6.0 **AutoRoute** aims for less generated code for more flexibility and less generation time. - -#### 1. Instead of using `MaterialAutoRouter`, `CupertinoAutoRouter`, etc, we now only have one annotation for our router which is `@AutoRouterConfig()` and instead of passing our routes list to the annotation we now pass it to the overridable getter `routes` inside of the generated router class and for the default route type you can override `defaultRouteType` - -#### Before - -```dart -// @CupertinoAutoRouter -// @AdaptiveAutoRouter -// @CustomAutoRouter -@MaterialAutoRouter( - routes: [ - // routes go here - ], -) -class $AppRouter {} -``` - -#### After - - ```dart -@AutoRouterConfig() -class AppRouter extends $AppRouter { - - @override - RouteType get defaultRouteType => RouteType.material(); //.cupertino, .adaptive ..etc - - @override - List get routes => [ - // routes go here - ]; -} -``` - -#### 2. Passing page components as types is changed, now you'd annotate the target page with `@RoutePage()` annotation and pass the generated `result.page` to AutoRoute(): - -#### Before - -```dart -class ProductDetailsPage extends StatelessWidget {} -``` - -```dart -AutoRoute(page: ProductDetailsPage) // as Type -``` - -#### After - -```dart -@RoutePage() // Add this annotation to your routable pages -class ProductDetailsPage extends StatelessWidget {} -``` - -```dart -AutoRoute(page: ProductDetailsRoute.page) // ProductDetailsRoute is generated -``` - -#### 3. `EmptyRoutePage` no longer exists, instead you will now make your own empty pages by extending the `AutoRouter` widget - -#### Before - -```dart -AutoRoute(page: EmptyRoutePage, name: 'ProductsRouter') // as Type -``` - -#### After - -```dart -@RoutePage(name: 'ProductsRouter') -class ProductsRouterPage extends AutoRouter {} -``` - -```dart -AutoRoute(page: ProductsRouter.page) -``` - -#### 4. Passing route guards is also changed now, instead of passing guards as types you now pass instances. - -#### Before - -```dart -AutoRoute(page: ProfilePage, guards:[AuthGuard]) // as Type -``` - -#### After - -```dart -AutoRoute(page: ProfilePage, guards:[AuthGuard()]) // as Instance -``` - ## Examples coming soon diff --git a/migrations/migrating_to_v6.md b/migrations/migrating_to_v6.md new file mode 100644 index 00000000..3b26b7ce --- /dev/null +++ b/migrations/migrating_to_v6.md @@ -0,0 +1,91 @@ +## Migrating to v6 + +In version 6.0 **AutoRoute** aims for less generated code for more flexibility and less generation time. + +#### 1. Instead of using `MaterialAutoRouter`, `CupertinoAutoRouter`, etc, we now only have one annotation for our router which is `@AutoRouterConfig()` and instead of passing our routes list to the annotation we now pass it to the overridable getter `routes` inside of the generated router class and for the default route type you can override `defaultRouteType` + +#### Before + +```dart +// @CupertinoAutoRouter +// @AdaptiveAutoRouter +// @CustomAutoRouter +@MaterialAutoRouter( + routes: [ + // routes go here + ], +) +class $AppRouter {} +``` + +#### After + + ```dart +@AutoRouterConfig() +class AppRouter extends $AppRouter { + + @override + RouteType get defaultRouteType => RouteType.material(); //.cupertino, .adaptive ..etc + + @override + List get routes => [ + // routes go here + ]; +} +``` + +#### 2. Passing page components as types is changed, now you'd annotate the target page with `@RoutePage()` annotation and pass the generated `result.page` to AutoRoute(): + +#### Before + +```dart +class ProductDetailsPage extends StatelessWidget {} +``` + +```dart +AutoRoute(page: ProductDetailsPage) // as Type +``` + +#### After + +```dart +@RoutePage() // Add this annotation to your routable pages +class ProductDetailsPage extends StatelessWidget {} +``` + +```dart +AutoRoute(page: ProductDetailsRoute.page) // ProductDetailsRoute is generated +``` + +#### 3. `EmptyRoutePage` no longer exists, instead you will now make your own empty pages by extending the `AutoRouter` widget + +#### Before + +```dart +AutoRoute(page: EmptyRoutePage, name: 'ProductsRouter') // as Type +``` + +#### After + +```dart +@RoutePage(name: 'ProductsRouter') +class ProductsRouterPage extends AutoRouter {} +``` + +```dart +AutoRoute(page: ProductsRouter.page) +``` + +#### 4. Passing route guards is also changed now, instead of passing guards as types you now pass instances. + +#### Before + +```dart +AutoRoute(page: ProfilePage, guards:[AuthGuard]) // as Type +``` + +#### After + +```dart +AutoRoute(page: ProfilePage, guards:[AuthGuard()]) // as Instance +``` \ No newline at end of file diff --git a/migrations/migrating_to_v9.md b/migrations/migrating_to_v9.md new file mode 100644 index 00000000..6fc15da2 --- /dev/null +++ b/migrations/migrating_to_v9.md @@ -0,0 +1,120 @@ +## Migrating to v9 + +#### 1. You now need to extend `RootStackRouter` from the `auto_route` package instead of the generated `$YOUR_APP_NAME`. + +#### Before + +```dart + +@AutoRouterConfig() +class AppRouter extends $AppRouter { + + @override + List get routes => [ + /// routes go here + ]; +} +``` +#### After + +```dart + +@AutoRouterConfig() +class AppRouter extends RootStackRouter { + + @override + List get routes => [ + /// routes go here + ]; +} +``` + +#### 2. You no longer need to provide the return type of a page inside `@RoutePage()` instead provide the return type as you push your page. + +#### Before + +```dart +@RoutePage() +class LoginPage extends StatelessWidget {} + +``` + +```dart + /// pushing the route +bool didLogin = await context.pushRoute(); +``` + +#### After + +```dart +/// provide the return type as you push your page + bool didLogin = await context.pushRoute(); +``` + +#### 3. Global guards are now provided as a list of `AutoRouteGuard` instead implementing `AutoRouteGuard` directly. + +#### Before + +```dart +@AutoRouterConfig() +class AppRouter extends $AppRouter implements AutoRouteGuard { + + @override + void onNavigation(NavigationResolver resolver, StackRouter router) { + /// guard logic + } + +} +``` +#### After + +```dart +@AutoRouterConfig() +class AppRouter extends RootStackRouter{ + final authGuard = AuthGuard(); + @override + late final List guards = [ + authGuard, /// guard instance + /// or use a simple guard wrapper + AutoRouteGuard.simple((resolver, router) { + /// guard logic + ), + + ]; +} +``` + +#### 4. AutoRouterConfig.module is no longer used, generated `PageRouteInfos` are now self-sufficient. they contain the page builder inside `PageRouteInfo.page`. +What you do now is generated the routes inside the micro package like normal, then either use the generated routes inside your main router individually, +or declare them inside your micro router then merge them with the main router. + +#### Before +```dart +@AutoRouterConfig.module() +class MyPackageModule extends $MyPackageModule {} +``` +```dart +@AutoRouterConfig(modules: [MyPackageModule]) +class AppRouter extends $AppRouter {} +``` + +#### After + +```dart +/// normal auto router config +@AutoRouterConfig() +class MyMicroRouter extends RootStackRouter{} +``` + +```dart + final myMicroRouter = MyMicroRouter(); + + @override + List get routes => [ + AutoRoute(page: HomeRoute.page, initial: true), + /// use micro routes individually + AutoRoute(page: RouteFromMicroPackage.page), + /// or merge all routes from micro router + ...myMicroRouter.routes, + ]; +``` \ No newline at end of file diff --git a/old/pre_v9_README.md b/old/pre_v9_README.md new file mode 100644 index 00000000..3628ea19 --- /dev/null +++ b/old/pre_v9_README.md @@ -0,0 +1,1622 @@ +

+ auto_route_logo +

+ +

+ + MIT License + + + stars + + + pub version + + + Discord Badge + +

+ +

+ + Buy Me A Coffee + +

+ +--- + +- [Introduction](#introduction) + - [Installation](#installation) + - [Setup and Usage](#setup-and-usage) +- [Generated routes](#generated-routes) +- [Navigation](#navigating-between-screens) + - [Navigating Between Screens](#navigating-between-screens) + - [Passing Arguments](#passing-arguments) + - [Returning Results](#returning-results) + - [Nested navigation](#nested-navigation) + - [Tab Navigation](#tab-navigation) + - [Using PageView](#using-pageview) + - [Using TabBar](#using-tabbar) + - [Finding The Right Router](#finding-the-right-router) + - [Navigating Without Context](#navigating-without-context) +- [Deep Linking](#deep-linking) +- [Declarative Navigation](#declarative-navigation) +- [Working with Paths](#working-with-paths) +- [Route guards](#route-guards) +- [Wrapping routes](#wrapping-routes) +- [Navigation Observers](#navigation-observers) +- [Customization](#customizations) + - [Custom Route Transitions](#custom-route-transitions) + - [Custom Route Builder](#custom-route-builder) +- [Others](#others) + - [Including Micro/External Packages](#including-microexternal-packages) + - [Configuring builders](#configuring-builders) + - [Optimizing Generation Time](#optimizing-generation-time) + - [Enabling Cached Builds (Experimental)](#enabling-cached-builds) + - [AutoLeadingButton-BackButton](#autoleadingbutton-backbutton) + - [ActiveGuardObserver](#activeguardobserver) +- [Examples](#examples) + +**Note:** [AutoRoute-Helper] is no longer supported. + +## Migration guides + +- [Migrating to v6](#migrating-to-v6) + +## Pre v6 documentation + +- [Pre v6 documentation](https://github.com/Milad-Akarie/auto_route_library/blob/master/old/pre_v6_README.md) + +## Introduction + +#### What is AutoRoute? + +It’s a Flutter navigation package, it allows for strongly-typed arguments passing, effortless deep-linking and it uses code generation to simplify routes setup. With that being said, it requires a minimal amount of code to generate everything needed for navigation inside of your App. + +#### Why AutoRoute? + +If your App requires deep-linking or guarded routes or just a clean routing setup, you'll need to use named/generated routes and you’ll end up writing a lot of boilerplate code for mediator argument classes, checking for required arguments, extracting arguments and a bunch of other stuff. **AutoRoute** does all that for you and much more. + +## Installation + + ```yaml +dependencies: + auto_route: [latest-version] + +dev_dependencies: + auto_route_generator: [latest-version] + build_runner: +``` + +## Setup And Usage + +1. Create a router class and annotate it with `@AutoRouterConfig` then extend "$YourClassName" +2. Override the routes getter and start adding your routes. + + ```dart +@AutoRouterConfig() +class AppRouter extends $AppRouter { + + @override + List get routes => [ + /// routes go here + ]; +} +``` + +### Using part builder + +To generate a part-of file simply add a `part` directive to your `AppRouter` and extend the generated private router. **Note:** The `deferredLoading` functionality does not work with part-file setup. + +```dart +part 'app_router.gr.dart'; + +@AutoRouterConfig() +class AppRouter extends _$AppRouter { + + @override + List get routes => [ + /// routes go here + ]; +} +``` + +### Generating Routable pages + +Routable pages are just simple everyday widgets annotated with `@RoutePage()` which allows them to be constructed by the router. + +```dart +@RoutePage() +class HomeScreen extends StatefulWidget {} +``` + +#### Now simply run the generator + +Use the [watch] flag to watch the files' system for edits and rebuild as necessary. + +```terminal +dart run build_runner watch +``` + +If you want the generator to run one time and exit, use + +```terminal +dart run build_runner build +``` + +#### Add the generated route to your routes list + +```dart +@AutoRouterConfig(replaceInRouteName: 'Screen,Route') +class AppRouter extends $AppRouter { + + @override + List get routes => [ + // HomeScreen is generated as HomeRoute because + // of the replaceInRouteName property + AutoRoute(page: HomeRoute.page), + ]; +} +``` + +#### Finalize the setup + +After you run the generator, your router class will be generated. Then simply hook it up with your MaterialApp. + +```dart +// assuming this is the root widget of your App +class App extends StatelessWidget { + // make sure you don't initiate your router + // inside of the build function. + final _appRouter = AppRouter(); + + @override + Widget build(BuildContext context){ + return MaterialApp.router( + routerConfig: _appRouter.config(), + ); + } +} +``` + +## Generated Routes + +A `PageRouteInfo` object will be generated for every declared **AutoRoute**. These objects hold strongly-typed page arguments which are extracted from the page's default constructor. Think of them as string path segments on steroids. + +```dart +class BookListRoute extends PageRouteInfo { + const BookListRoute({ + List? children, + }) : super(name, path: '/books', initialChildren: children); + + static const String name = 'BookListRoute'; + static const PageInfo page = PageInfo(name); +} +``` + +## Navigating Between Screens + +`AutoRouter` offers the same known push, pop and friends methods to manipulate the pages stack using both the generated `PageRouteInfo` objects and paths. + +```dart +// get the scoped router by calling +AutoRouter.of(context); +// or using the extension +context.router; +// adds a new entry to the pages stack +router.push(const BooksListRoute()); +// or by using paths +router.pushNamed('/books'); +// removes last entry in stack and pushes provided route +// if last entry == provided route page will just be updated +router.replace(const BooksListRoute()); +// or by using paths +router.replaceNamed('/books'); +// pops until provided route, if it already exists in stack +// else adds it to the stack (good for web Apps). +router.navigate(const BooksListRoute()); +// or by using paths +router.navigateNamed('/books'); +// on Web it calls window.history.back(); +// on Native it navigates you back +// to the previous location +router.back(); +// adds a list of routes to the pages stack at once +router.pushAll([ + BooksListRoute(), + BookDetailsRoute(id: 1), +]); +// This is like providing a completely new stack as it rebuilds the stack +// with the list of passed routes +// entries might just update if already exist +router.replaceAll([ + LoginRoute(), +]); +// pops the last page unless blocked or stack has only 1 entry +context.router.maybePop(); +// pops the most top page of the most top router unless blocked +// or stack has only 1 entry +context.router.maybePopTop(); +// keeps popping routes until predicate is satisfied +context.router.popUntil((route) => route.settings.name == 'HomeRoute'); +// a simplified version of the above line +context.router.popUntilRouteWithName('HomeRoute'); +// keeps popping routes until route with provided path is found +context.router.popUntilRouteWithPath('/some-path'); +// pops all routes down to the root +context.router.popUntilRoot(); +// removes the top most page in stack even if it's the last +// remove != pop, it doesn't respect WillPopScopes it just +// removes the entry. +context.router.removeLast(); +// removes any route in stack that satisfies the predicate +// this works exactly like removing items from a regular List +// [...].removeWhere((r)=>) +context.router.removeWhere((route) => ); +// you can also use the common helper methods from context extension to navigate +context.pushRoute(const BooksListRoute()); +context.replaceRoute(const BooksListRoute()); +context.navigateTo(const BooksListRoute()); +context.navigateNamedTo('/books'); +context.back(); +context.maybePop(); +``` + +## Passing Arguments + +That's the fun part! **AutoRoute** automatically detects and handles your page arguments for you, the generated route object will deliver all the arguments your page needs including path/query params. + +e.g. The following page widget will take an argument of type `Book`. + +```dart +@RoutePage() +class BookDetailsPage extends StatelessWidget { + const BookDetailsPage({required this.book}); + + final Book book; + ... +``` + +**Note:** Default values are respected. Required fields are also respected and handled properly. + +The generated `BookDetailsRoute` will deliver the same arguments to its corresponding page. + +```dart +router.push(BookDetailsRoute(book: book)); +``` + +**Note:** All arguments are generated as named parameters regardless of their original type. + +## Returning Results + +You can return results by either using the pop completer or by passing a callback function as an argument the same way you'd pass an object. + +#### 1. Using the `pop` completer + +```dart +var result = await router.push(LoginRoute()); +``` + +then inside of your `LoginPage`, pop with results + +```dart +router.maybePop(true); +``` + +as you'd notice we did not specify the result type, we're playing with dynamic values here, which can be risky and I personally don't recommend it. + +To avoid working with dynamic values, we specify what type of results we expect our page to return, which is a `bool` value. + +```dart +@RoutePage() +class LoginPage extends StatelessWidget {} +``` + +we push and specify the type of results we're expecting + +```dart +var result = await router.push(LoginRoute()); +``` + +and of course we pop with the same type + +```dart +router.maybePop(true); +``` + +#### 2. Passing a callback function as an argument. +We only have to add a callback function as a parameter to our page constructor like follows: + +```dart +@RoutePage() +class BookDetailsPage extends StatelessWidget { + const BookDetailsRoute({this.book, required this.onRateBook}); + + final Book book; + final void Function(int) onRateBook; + ... +``` + +The generated `BookDetailsRoute` will deliver the same arguments to its corresponding page. + +```dart +context.pushRoute( + BookDetailsRoute( + book: book, + onRateBook: (rating) { + // handle result + }, + ), +); +``` + +If you're finishing with results, make sure you call the callback function as you pop the page + +```dart +onRateBook(RESULT); +context.maybePop(); +``` + +**Note:** Default values are respected. Required fields are also respected and handled properly. + +## Nested Navigation + +Nested navigation means building an inner router inside of a page of another router, for example in the below diagram users page is built inside of dashboard page. + +

+ nested-router-demo +

+ +Defining nested routes is as easy as populating the children field of the parent route. In the following example `UsersPage`, `PostsPage` and `SettingsPage` are nested children of `DashboardPage`. + +```dart +@AutoRouterConfig(replaceInRouteName: 'Page,Route') +class AppRouter extends $AppRouter { + +@override +List get routes => [ + AutoRoute( + path: '/dashboard', + page: DashboardRoute.page, + children: [ + AutoRoute(path: 'users', page: UsersRoute.page), + AutoRoute(path: 'posts', page: PostsRoute.page), + AutoRoute(path: 'settings', page: SettingsRoute.page), + ], + ), + AutoRoute(path: '/login', page: LoginRoute.page), + ]; +} +``` + +To render/build nested routes we need an `AutoRouter` widget that works as an outlet or a nested router-view inside of our dashboard page. + +```dart +class DashboardPage extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Column( + children: [ + NavLink(label: 'Users', destination: const UsersRoute()), + NavLink(label: 'Posts', destination: const PostsRoute()), + NavLink(label: 'Settings', destination: const SettingsRoute()), + ], + ), + Expanded( + // nested routes will be rendered here + child: AutoRouter(), + ), + ], + ); + } +} +``` + +**Note** NavLink is just a button that calls router.push(destination). Now if we navigate to `/dashboard/users`, we will be taken to the `DashboardPage` and the `UsersPage` will be shown inside of it. + +What if want to show one of the child pages at `/dashboard`? We can simply do that by giving the child routes an empty path `''` to make initial or by setting initial to true. + +```dart +AutoRoute( + path: '/dashboard', + page: DashboardRoute.page, + children: [ + AutoRoute(path: '', page: UsersRoute.page), + AutoRoute(path: 'posts', page: PostsRoute.page), + ], +) +``` + +or by using a `RedirectRoute` + +```dart +AutoRoute( + path: '/dashboard', + page: DashboardRoute.page, + children: [ + RedirectRoute(path: '', redirectTo: 'users'), + AutoRoute(path: 'users', page: UsersRoute.page), + AutoRoute(path: 'posts', page: PostsRoute.page), + ], +) +``` + +### Things to keep in mind when implementing nested navigation + +1. Each router manages its own pages stack. +2. Navigation actions like push, pop and friends are handled by the topmost router and bubble up if it couldn't be handled. + +## Tab Navigation + +If you're working with flutter mobile, you're most likely to implement tabs navigation, that's why `auto_route` makes tabs navigation as easy and straightforward as possible. + +In the previous example we used an `AutoRouter` widget to render nested child routes, `AutoRouter` is just a shortcut for `AutoStackRouter`. `StackRouters` manage a stack of pages inside of them, where the active/visible page is always the one on top and you'd need to pop it to see the page beneath it. + +Now we can try to implement our tabs using an `AutoRouter` (StackRouter) by pushing or replacing a nested route every time the tab changes and that might work, but our tabs state will be lost, not to mention the transition between tabs issue, luckily auto_route comes equipped with an `AutoTabsRouter`, which is especially made to handle tab navigation. + +`AutoTabsRouter` lets you switch between different routes while preserving offstage-routes state, tab routes are lazily loaded by default (can be disabled) and it finally allows to create whatever transition animation you want. + +Let's change the previous example to use tab navigation. + +Notice that we're not going to change anything in our routes declaration map, we still have a dashboard page that has three nested children: users, posts and settings. + +```dart +class DashboardPage extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return AutoTabsRouter( + // list of your tab routes + // routes used here must be declared as children + // routes of /dashboard + routes: const [ + UsersRoute(), + PostsRoute(), + SettingsRoute(), + ], + transitionBuilder: (context,child,animation) => FadeTransition( + opacity: animation, + // the passed child is technically our animated selected-tab page + child: child, + ), + builder: (context, child) { + // obtain the scoped TabsRouter controller using context + final tabsRouter = AutoTabsRouter.of(context); + // Here we're building our Scaffold inside of AutoTabsRouter + // to access the tabsRouter controller provided in this context + // + // alternatively, you could use a global key + return Scaffold( + body: child, + bottomNavigationBar: BottomNavigationBar( + currentIndex: tabsRouter.activeIndex, + onTap: (index) { + // here we switch between tabs + tabsRouter.setActiveIndex(index); + }, + items: [ + BottomNavigationBarItem(label: 'Users', ...), + BottomNavigationBarItem(label: 'Posts', ...), + BottomNavigationBarItem(label: 'Settings', ...), + ], + ), + ); + }, + ); + } +} +``` + +If you think the above setup is a bit messy you could use the shipped-in `AutoTabsScaffold` that makes things much cleaner. + +```dart +class DashboardPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AutoTabsScaffold( + routes: const [ + UsersRoute(), + PostsRoute(), + SettingsRoute(), + ], + bottomNavigationBuilder: (_, tabsRouter) { + return BottomNavigationBar( + currentIndex: tabsRouter.activeIndex, + onTap: tabsRouter.setActiveIndex, + items: const [ + BottomNavigationBarItem(label: 'Users', ...), + BottomNavigationBarItem(label: 'Posts', ...), + BottomNavigationBarItem(label: 'Settings', ...), + ], + ); + }, + ); + } +} +``` + +### Using PageView + +Use the `AutoTabsRouter.pageView` constructor to implement tabs using PageView + +```dart +AutoTabsRouter.pageView( + routes: [ + BooksTab(), + ProfileTab(), + SettingsTab(), + ], + builder: (context, child, _) { + final tabsRouter = AutoTabsRouter.of(context); + return Scaffold( + appBar: AppBar( + title: Text(context.topRoute.name), + leading: AutoLeadingButton(), + ), + body: child, + bottomNavigationBar: BottomNavigationBar( + currentIndex: tabsRouter.activeIndex, + onTap: tabsRouter.setActiveIndex, + items: [ + BottomNavigationBarItem(label: 'Books', ...), + BottomNavigationBarItem(label: 'Profile', ...), + BottomNavigationBarItem(label: 'Settings', ...), + ], + ), + ); + }, +); +``` + +### Using TabBar + +Use the `AutoTabsRouter.tabBar` constructor to implement tabs using TabBar + +```dart +AutoTabsRouter.tabBar( + routes: [ + BooksTab(), + ProfileTab(), + SettingsTab(), + ], + builder: (context, child, controller) { + final tabsRouter = AutoTabsRouter.of(context); + return Scaffold( + appBar: AppBar( + title: Text(context.topRoute.name), + leading: AutoLeadingButton(), + bottom: TabBar( + controller: controller, + tabs: const [ + Tab(text: '1', icon: Icon(Icons.abc)), + Tab(text: '2', icon: Icon(Icons.abc)), + Tab(text: '3', icon: Icon(Icons.abc)), + ], + ), + ), + body: child, + bottomNavigationBar: BottomNavigationBar( + currentIndex: tabsRouter.activeIndex, + onTap: tabsRouter.setActiveIndex, + items: [ + BottomNavigationBarItem(label: 'Books',...), + BottomNavigationBarItem(label: 'Profile',...), + BottomNavigationBarItem(label: 'Settings',...), + ], + ), + ); + }, +); +``` + +## Finding The Right Router + +Every nested `AutoRouter` has its own routing controller to manage the stack inside of it and the easiest way to obtain a scoped controller is by using the `BuildContext`. + +In the previous example, `DashboardPage` is a root level stack entry so calling `AutoRouter.of(context)` anywhere inside of it will get us the root routing controller. + +`AutoRouter` widgets that are used to render nested routes, insert a new router scope into the widgets tree, so when a nested route calls for the scoped controller, they will get the closest parent controller in the widgets tree; not the root controller. + +```dart +class Dashboard extends StatelessWidget { + + @override + Widget build(BuildContext context) { + // this will get us the root routing controller + AutoRouter.of(context); + return Scaffold( + appBar: AppBar(title: Text('Dashboard page')), + // this inserts a new router scope into the widgets tree + body: AutoRouter() + ); + } +} +``` + +Here's a simple diagram to help visualize this + +

+ scoped-router-demo +

+ +As you can tell from the above diagram it's possible to access parent routing controllers by calling `router.parent()`, we're using a generic function because we have two different routing controllers: `StackRouter` and `TabsRouter`, one of them could be the parent controller of the current router and that's why we need to specify a type. + +```dart +router.parent() // this returns the parent router as a Stack Routing controller +router.parent() // this returns the parent router as a Tabs Routing controller +``` + +On the other hand, obtaining the root controller does not require type casting because it's always a `StackRouter`. + +```dart +router.root // this returns the root router as a Stack Routing controller +``` + +You can obtain access to inner-routers from outside their scope using a global key + +```dart +class DashboardPage extends StatefulWidget { + @override + _DashboardPageState createState() => _DashboardPageState(); +} + +class _DashboardPageState extends State { + final _innerRouterKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Column( + children: [ + NavLink( + label: 'Users', + onTap: () { + final router = _innerRouterKey.currentState?.controller; + router?.push(const UsersRoute()); + }, + ), + ... + ], + ), + Expanded( + child: AutoRouter(key: _innerRouterKey), + ), + ], + ); + } +} +``` + +You could also obtain access to inner-routers from outside their scope without a global key, as long as they're initiated. + +```dart +// assuming this is the root router +context.innerRouterOf(UserRoute.name); +// or if we're using an AutoTabsRouter inside of DashboardPage +context.innerRouterOf(UserRoute.name); +``` + +Accessing the `DashboardPage` inner router from the previous example. + +```dart +class Dashboard extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Dashboard'), + actions: [ + IconButton( + icon: Icon(Icons.person), + onPressed: () { + // accessing the inner router from + // outside the scope + final router = context.innerRouterOf(DashboardRoute.name) + router?.push(const UsersRoute()); + }, + ), + ], + ), + body: AutoRouter(), // we're trying to get access to this + ); + } +} +``` + +## Navigating Without Context + +To navigate without context you can simply assign your generated router to a global variable + +```dart +// declare your route as a global variable +final appRouter = AppRouter(); + +class MyApp extends StatefulWidget { + + @override + Widget build(BuildContext context) { + return MaterialApp.router( + routerConfig: appRouter.config(), + ); + } +} +``` + +**Note:** Using global variable is not recommended and is considered bad practice and most of the times you should use dependency injection instead. + +Here's an example using `get_it` (which is just a personal favorite). You can use any dependency injection package you like. + +```dart +void main(){ + // make sure you register it as a Singleton or a lazySingleton + getIt.registerSingleton(AppRouter()); + runApp(MyApp()); +} + +class MyApp extends StatefulWidget { + @override + Widget build(BuildContext context) { + final appRouter = getIt(); + + return MaterialApp.router( + routerConfig: appRouter.config(), + ); + } +} +``` + +Now you can access your router anywhere inside of your app without using context. + +```dart +getIt().push(...); +``` + +**Note:** Navigating without context is not recommended in nested navigation unless you use `navigate` instead of `push` and you provide a full hierarchy, e.g `router.navigate(SecondRoute(children: [SubChild2Route()]))` + +## Deep Linking + +**AutoRoute** will automatically handle deep-links coming from the platform, but native platforms require some setup, see [Deep linking topic](https://docs.flutter.dev/ui/navigation/deep-linking) in flutter documentation. + +### Using Deep-link Transformer + +Deep link transformer intercepts deep-links before they're processed by the matcher, it's useful for stripping or modifying deep-links before they're matched. + +In the following example we will strip a prefix from the deep-link before it's matched. + +```dart +MaterialApp.router( + routerConfig: _appRouter.config( + deepLinkTransformer: (uri) { + if (uri.path.startsWith('/prefix')) { + return SynchronousFuture( + uri.replace(path: uri.path.replaceFirst('/prefix', '')), + ); + } + return SynchronousFuture(uri); + } + ), +); +``` +**Note** for prefix stripping use the shipped-in `DeepLink.prefixStripper('prefix')` + +```dart +MaterialApp.router( + routerConfig: _appRouter.config( + deepLinkTransformer: DeepLink.prefixStripper('prefix'), + ), +); +``` + +```dart +### Using Deep-link Builder + +Deep link builder is an interceptor for deep-links where you can validate or override deep-links coming from the platform. + +In the following example we will only allow deep-links starting with `/products` + +```dart +MaterialApp.router( + routerConfig: _appRouter.config( + deepLinkBuilder: (deepLink) { + if (deepLink.path.startsWith('/products')) { + // continue with the platform link + return deepLink; + } else { + return DeepLink.defaultPath; + // or DeepLink.path('/') + // or DeepLink([HomeRoute()]) + } + } + ), +); +``` + +### Deep Linking to non-nested Routes + +**AutoRoute** can build a stack from a linear route list as long as they're ordered properly and can be matched as prefix, e.g `/` is a prefix match of `/products`, and `/products` is prefix match of `/products/:id`. Then we have a setup that looks something like this: +- `/` +- `/products` +- `/products/:id` + +Now, receiving this deep-link `/products/123` will add all above routes to the stack. This of course requires `includePrefixMatches` to be true in the root config (default is `!kWeb`) or when using `pushNamed`, `navigateNamed` and `replaceNamed`. + +**Things to keep in mind**: + +- If a full match can not finally be found, no prefix matches will be included. +- Paths that require a full path match => `AutoRoute(path:'path', fullMatch: true)` will not be + included as prefix matches. +- In the above example, if `/products/:id` comes before `/products`, `/products` will not be + included. + +## Declarative Navigation + +To use declarative navigation with auto_route, you simply use the `AutoRouter.declarative` constructor and return a list of routes based on state. + +```dart +AutoRouter.declarative( + routes: (handler) => [ + BookListRoute(), + if(_selectedBook != null) { + BookDetailsRoute(id: _selectedBook.id), + } + ], +); +``` + +**Note:** The handler contains a temp-list of pending initial routes which can be read only once. + +## Working with Paths + +Working with paths in **AutoRoute** is optional because `PageRouteInfo` objects are matched by name unless pushed as a string using the `deepLinkBuilder` property in root delegate or `pushNamed`, `replaceNamed` `navigateNamed` methods. + +If you don’t specify a path it’s going to be generated from the page name e.g. `BookListPage` will have ‘book-list-page’ as a path, if initial arg is set to true the path will be `/`, unless it's relative then it will be an empty string `''`. + +When developing a web application or a native app that requires deep-linking, you'd probably need to define paths with clear memorable names, and that's done using the `path` argument in `AutoRoute`. + +```dart +AutoRoute(path: '/books', page: BookListPage), +``` + +### Path Parameters (dynamic segments) + +You can define a dynamic segment by prefixing it with a colon + +```dart +AutoRoute(path: '/books/:id', page: BookDetailsPage), +``` + +The simplest way to extract path parameters from path and gain access to them is by annotating constructor params with `@PathParam('optional-alias')` with the same alias/name of the segment. + +```dart +class BookDetailsPage extends StatelessWidget { + const BookDetailsPage({@PathParam('id') this.bookId}); + + final int bookId; + ... +} +``` + +Now writing `/books/1` in the browser will navigate you to `BookDetailsPage` and automatically extract the `bookId` argument from path and inject it to your widget. + +#### Inherited Path Parameters + +To inherit a path-parameter from a parent route's path, we need to use `@PathParam.inherit` annotation in the child route's constructor. Let's say we have the following setup: + +```dart +AutoRoute( + path: '/product/:id', + page: ProductRoute.page, + children: [ + AutoRoute(path: 'review',page: ProductReviewRoute.page), + ], +) +``` + +Now `ProductReviewScreen` expects a path-param named `id` but, from the above snippet we know that the path corresponding with it. `review` has no path parameters, but we can inherit 'id' from the parent `/product/:id` like follows: + +```dart +@RoutePage() +class ProductReviewScreen extends StatelessWidget { + // the path-param 'id' will be inherited and it can not be passed + // as a route arg by user + const ProductReviewScreen({super.key, @PathParam.inherit('id') required String id}); +} +``` + +### Query Parameters + +Query parameters are accessed the same way, simply annotate the constructor parameter to hold the value of the query param with `@QueryParam('optional-alias')` and let **AutoRoute** do the rest. + +You could also access path/query parameters using the scoped `RouteData` object. + +```dart +RouteData.of(context).pathParams; +// or using the extension +context.routeData.queryParams; +``` + +`Tip`: if your parameter name is the same as the path/query parameter, you could use the const `@pathParam` or `@queryParam` and not pass a slug/alias. + +```dart +@RoutePage() +class BookDetailsPage extends StatelessWidget { + const BookDetailsPage({@pathParam this.id}); + + final int id; + ... +} +``` + +### Redirecting Paths + +Paths can be redirected using `RedirectRoute`. The following setup will navigate us to `/books` when `/` is matched. + +```dart + [ + RedirectRoute(path: '/', redirectTo: '/books'), + AutoRoute(path: '/books', page: BookListRoute.page), +] +``` + +When redirecting initial routes the above setup can be simplified by setting the `/books` path as initial and **AutoRoute** will automatically generate the required redirect code for you. + +```dart + [ + AutoRoute(path: '/books', page: BookListRoute.page, initial: true), +] +``` + +You can also redirect paths with params like follows: + +```dart + [ + RedirectRoute(path: 'books/:id', redirectTo: '/books/:id/details'), + AutoRoute(path: '/books/:id/details', page: BookDetailsRoute.page), +] +``` + +**Note**: `RedirectRoutes` are fully matched. + +### Wildcards + +**AutoRoute** supports wildcard matching to handle invalid or undefined paths. + +```dart +AutoRoute( + path: '*', + page: UnknownRoute.page, +) +// it could be used with defined prefixes +AutoRoute( + path: '/profile/*', + page: ProfileRoute.page, +) +// or it could be used with RedirectRoute +RedirectRoute( + path: '*', + redirectTo: '/', +) +``` + +**Note:** Be sure to always add your wildcards at the end of your route list because routes are matched in order. + +## Route Guards + +Think of route guards as middleware or interceptors, routes can not be added to the stack without going through their assigned guards. Guards are useful for restricting access to certain routes. + +We create a route guard by extending `AutoRouteGuard` from the **AutoRoute** package and implementing our logic inside of the onNavigation method. + +```dart +class AuthGuard extends AutoRouteGuard { + + @override + void onNavigation(NavigationResolver resolver, StackRouter router) { + // the navigation is paused until resolver.next() is called with either + // true to resume/continue navigation or false to abort navigation + if(authenticated) { + // if user is authenticated we continue + resolver.next(true); + } else { + // we redirect the user to our login page + // tip: use resolver.redirect to have the redirected route + // automatically removed from the stack when the resolver is completed + resolver.redirect( + LoginRoute(onResult: (success) { + // if success == true the navigation will be resumed + // else it will be aborted + resolver.next(success); + }, + ); + ); + } + } +} +``` + +**Important**: `resolver.next()` should only be called once. + +The `NavigationResolver` object contains the guarded route which you can access by calling the property `resolver.route` and a list of pending routes (if there are any) accessed by calling `resolver.pendingRoutes`. + +Now we assign our guard to the routes we want to protect. + +```dart +AutoRoute( + page: ProfileRoute.page, + guards: [AuthGuard()], +); +``` + +#### Guarding all stack-routes + +You can have all your stack-routes (non-tab-routes) go through a global guard by having your router implement an AutoRouteGuard. Lets say you have an app with no publish screens, we'd have a global guard that only allows navigation if the user is authenticated or if we're navigating to the LoginRoute. + +```dart +@AutoRouterConfig() +class AppRouter extends $AppRouter implements AutoRouteGuard { + + @override + void onNavigation(NavigationResolver resolver, StackRouter router) { + if(isAuthenticated || resolver.route.name == LoginRoute.name) { + // we continue navigation + resolver.next(); + } else { + // else we navigate to the Login page so we get authenticated + + // tip: use resolver.redirect to have the redirected route + // automatically removed from the stack when the resolver is completed + resolver.redirect(LoginRoute(onResult: (didLogin) => resolver.next(didLogin))); + } + } + // ..routes[] +} +``` + + + +### Using a Reevaluate Listenable + +Route guards can prevent users from accessing private pages until they're logged in for example, but auth state may change when the user is already navigated to the private page, to make sure private pages are only accessed by logged-in users all the time, we need a listenable that tells the router that the auth state has changed and you need to re-evaluate your stack. + +The following auth provider mock will act as our re-valuate listenable + +```dart +class AuthProvider extends ChangeNotifier { + bool _isLoggedIn = false; + + bool get isLoggedIn => _isLoggedIn; + + void login() { + _isLoggedIn = true; + notifyListeners(); + } + + void logout() { + _isLoggedIn = false; + notifyListeners(); + } +} +``` + +We simply pass an instance of our `AuthProvider` to `reevaluateListenable` inside of `router.config` + +```dart +MaterialApp.router( + routerConfig: _appRouter.config( + reevaluateListenable: authProvider, + ), +); +``` + +Now, every time `AutoProvider` notifies listeners, the stack will be re-evaluated and `AutoRouteGuard.onNavigation()`. Methods will be re-called on all guards + +In the above example, we assigned our `AuthProvider` to `reevaluateListenable` directly, that's because `reevaluateListenable` takes a `Listenable` and AuthProvider extends `ChangeNotifier` which is a `Listenable`, if your auth provider is a stream you can use `reevaluateListenable: ReevaluateListenable.stream(YOUR-STREAM)` + +**Note**: When the Stack is re-evaluated, the whole existing hierarchy will be re-pushed, so if you want to stop re-evaluating routes at some point, use `resolver.resolveNext()` which is like `resolver.next()` but with more options. + +```dart +@override +void onNavigation(NavigationResolver resolver, StackRouter router) async { + if (authProvider.isAuthenticated) { + resolver.next(); + } else { + resolver.redirect( + WebLoginRoute( + onResult: (didLogin) { + // stop re-pushing any pending routes after current + resolver.resolveNext(didLogin, reevaluateNext: false); + }, + ), + ); + } +} +``` + +## Wrapping Routes + +In some cases we want to wrap our screen with a parent widget, usually to provide some values through context, e.g wrapping your route with a custom `Theme` or a `Provider`. To do that, simply implement `AutoRouteWrapper`, and have wrappedRoute(context) method return (this) as the child of your wrapper widget. + +```dart +@RoutePage() +class ProductsScreen extends StatelessWidget implements AutoRouteWrapper { + + @override + Widget wrappedRoute(BuildContext context) { + return Provider(create: (ctx) => ProductsBloc(), child: this); + } + ... +} +``` + + + +## Navigation Observers + +Navigation observers are used to observe when routes are pushed ,replaced or popped ..etc. + +We implement an AutoRouter observer by extending an `AutoRouterObserver` which is just a `NavigatorObserver` with tab route support. + +```dart +class MyObserver extends AutoRouterObserver { + + @override + void didPush(Route route, Route? previousRoute) { + print('New route pushed: ${route.settings.name}'); + } + + // only override to observer tab routes + @override + void didInitTabRoute(TabPageRoute route, TabPageRoute? previousRoute) { + print('Tab route visited: ${route.name}'); + } + + @override + void didChangeTabRoute(TabPageRoute route, TabPageRoute previousRoute) { + print('Tab route re-visited: ${route.name}'); + } +} +``` + +Then we pass our observer to the `.config().` **Important:** Notice that `navigatorObservers` property is a builder function that returns a list of observers and the reason for that is a navigator observer instance can only be used by a single router, so unless you're using a single router or you don't want your nested routers to inherit observers, make sure navigatorObservers builder always returns fresh observer instances. + +```dart +return MaterialApp.router( + routerConfig: _appRouter.config( + navigatorObservers: () => [MyObserver()], + ), +); +``` + +The following approach **won't** work if you have nested routers unless they don't inherit the observers. + +```dart +final _observer = MyObserver(); +return MaterialApp.router( + routerConfig: _appRouter.config( + // this should always return new instances + navigatorObservers: () => [_observer], + ), +); +``` + +Every nested router can have it's own observers and inherit it's parent's. + +```dart +AutoRouter( + inheritNavigatorObservers: true, // true by default + navigatorObservers:() => [list of observers], +); + +AutoTabsRouter( + inheritNavigatorObservers: true, // true by default + navigatorObservers:() => [list of observers], +); +``` + +We can also make a certain screen **route** aware by subscribing to an `AutoRouteObserver` (route not router). + +First we provide our `AutoRouteObserver` instance + +```dart +return MaterialApp.router( + routerConfig: _appRouter.config( + navigatorObservers: () => [AutoRouteObserver()], + ), +); +``` + +Next, we use an `AutoRouteAware` mixin which is a `RouteAware` mixin with tab support to provide the needed listeners, then subscribe to our `AutoRouteObserver`. + +```dart +class BooksListPage extends State with AutoRouteAware { + AutoRouteObserver? _observer; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // RouterScope exposes the list of provided observers + // including inherited observers + _observer = RouterScope.of(context).firstObserverOfType(); + if (_observer != null) { + // we subscribe to the observer by passing our + // AutoRouteAware state and the scoped routeData + _observer.subscribe(this, context.routeData); + } + } + + @override + void dispose() { + super.dispose(); + // don't forget to unsubscribe from the + // observer on dispose + _observer.unsubscribe(this); + } + + // only override if this is a tab page + @override + void didInitTabRoute(TabPageRoute? previousRoute) {} + + // only override if this is a tab page + @override + void didChangeTabRoute(TabPageRoute previousRoute) {} + + @override + void didPopNext() {} + + @override + void didPushNext() {} + + @override + void didPush() {} + + @override + void didPop() {} +} +``` + +#### AutoRouteAwareStateMixin + +The above code can be simplified using `AutoRouteAwareStateMixin` + +```dart +class BooksListPage extends State with AutoRouteAwareStateMixin { + // only override if this is a tab page + @override + void didInitTabRoute(TabPageRoute? previousRoute) {} + + // only override if this is a tab page + @override + void didChangeTabRoute(TabPageRoute previousRoute) {} + + // only override if this is a stack page + @override + void didPopNext() {} + + // only override if this is a stack page + @override + void didPushNext() {} +} +``` + +## Customizations + +##### MaterialAutoRouter | CupertinoAutoRouter | AdaptiveAutoRouter + +| Property | Default value | Definition | +|-----------------------------|-----------------------|-----------------------------------------------------------------------------------| +| replaceInRouteName [String] | Page|Screen,Route | Used to replace conventional words in generated route name (pattern, replacement) | + +## Custom Route Transitions + +To use custom route transitions use a `CustomRoute` and pass in your preferences. The `TransitionsBuilder` function needs to be passed as a static/const reference that has the same signature as the `TransitionsBuilder` function of the `PageRouteBuilder` class. + +```dart +CustomRoute( + page: LoginRoute.page, + // TransitionsBuilders class contains a preset of common transitions builders. + transitionsBuilder: TransitionsBuilders.slideBottom, + durationInMilliseconds: 400, +) +``` + +`Tip:` Override `defaultRouteType` in generated router to define global custom route transitions. + +You can of course use your own transitionsBuilder function, as long as it has the same function signature. The function has to take in exactly one `BuildContext`, `Animation`, `Animation` and a child `Widget` and it needs to return a `Widget`. Typically, you would wrap your child with one of Flutter's transition widgets as follows: + +```dart +CustomRoute( + page: ZoomInScreen, + transitionsBuilder: + (BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { + // you get an animation object and a widget + // make your own transition + return ScaleTransition(scale: animation, child: child); + }, +) +``` + +## Custom Route Builder + +You can use your own custom route by passing a `CustomRouteBuilder` function to `CustomRoute' and implement the builder function the same way we did with the TransitionsBuilder function, the most important part here is passing the page argument to our custom route. + +```dart +CustomRoute( + page: CustomPage, + customRouteBuilder: (BuildContext context, Widget child, CustomPage page) { + return PageRouteBuilder( + fullscreenDialog: page.fullscreenDialog, + // this is important + settings: page, + pageBuilder: (_,__,___) => child, + ); + }, +) +``` + +## Others + +### Including Micro/External Packages + +To include routes inside of a depended-on package, that package needs to generate an `AutoRouterModule` that will be later consumed by the root router. + +To have a package output an `AutoRouterModule` instead of a `RootStackRouter`, we need to use the `AutoRouterConfig.module()` annotation like follows + +```dart +@AutoRouterConfig.module() +class MyPackageModule extends $MyPackageModule {} +``` + +Then when setting up our root router we need to tell it to include the generated module. + +```dart +@AutoRouterConfig(modules: [MyPackageModule]) +class AppRouter extends $AppRouter {} +``` + +Now you can use `PageRouteInfos` generated inside `MyPackageModule`. + +`Tip:` You can add export `MyPackageModule` to `app_router.dart`, so you only import `app_router.dart` inside of your code. + +```dart +// ...imports +export 'package:my_package/my_package_module.dart' +@AutoRouterConfig(modules: [MyPackageModule]) +class AppRouter extends $AppRouter {} +``` + +## Configuring builders +To pass builder configuration to `auto_route_generator` we need to add `build.yaml` file next to `pubspec.yaml` if not already added. + +```yaml +targets: + $default: + builders: + auto_route_generator:auto_route_generator: + # configs for @RoutePage() generator ... + auto_route_generator:auto_router_generator: + # configs for @AutoRouterConfig() generator ... +``` + +### Passing custom ignore_for_file rules +You can pass custom ignore_for_file rules to the generated router by adding the following: + +```yaml +targets: + $default: + builders: + auto_route_generator:auto_router_generator: + options: + ignore_fore_file: + - custom_rule_1 + - custom_rule_2 +``` + +### Optimizing generation time +The first thing you want to do to reduce generation time, is specifying the files build_runner should process and we do that by using [globs](https://pub.dev/packages/glob). Globs are kind of regex patterns with little differences that's used to match file names. **Note:** for this to work on file level you need to follow a naming convention + +``` +let's say we have the following files tree +├── lib +│ ├── none_widget_file.dart +│ ├── none_widget_file2.dart +│ └── ui +│ ├── products_screen.dart +│ ├── products_details_screen.dart +``` + +By default, the builder will process all of these files to check for a page with `@RoutePage()` +annotation, we can help by letting it know what files we need processed, e.g only process the files +inside the ui folder: +**Note** (**) matches everything including '/'; + +```yaml +targets: + $default: + builders: + auto_route_generator:auto_route_generator: + generate_for: + - lib/ui/**.dart +``` + +Let's say you have widget files inside of the ui folder, but we only need to process files ending with `_screen.dart` + +```yaml +targets: + $default: + builders: + auto_route_generator:auto_route_generator: + generate_for: + - lib/ui/**_screen.dart +``` + +Now only `products_screen.dart`, `products_details_screen.dart` will be processed + +The same goes for `@AutoRouterConfig` builder + +```yaml +targets: + $default: + builders: + auto_route_generator:auto_route_generator: # this for @RoutePage + generate_for: + - lib/ui/**_screen.dart + auto_route_generator:auto_router_generator: # this for @AutoRouterConfig + generate_for: + - lib/ui/router.dart +``` + +## Enabling cached builds + +**This is still experimental** +When cached builds are enabled, **AutoRoute** will try to prevent redundant re-builds by analyzing whether the file changes has any effect on the extracted route info, e.g any changes inside of the build method should be ignored. + +**Note** Enable cached builds on both generators + +```yaml +targets: + $default: + builders: + auto_route_generator:auto_route_generator: # this for @RoutePage + options: + enable_cached_builds: true + generate_for: + - lib/ui/**_screen.dart + auto_route_generator:auto_router_generator: # this for @AutoRouterConfig + options: + enable_cached_builds: true + generate_for: + - lib/ui/router.dart +``` + +### AutoLeadingButton-BackButton + +`AutoLeadingButton` is **AutoRoute**'s replacement to the default BackButton to handle nested or parent stack popping. To use it, simply assign it to the `leading` property inside of `AppBar` + +```dart +AppBar( + title: Text(context.topRoute.name), + leading: AutoLeadingButton(), +) +``` + +### ActiveGuardObserver + +`ActiveGuardObserver` can notify you when a guard is being checked and what guard it is. This can be used to implement a loading indicator for example. + +```dart +var isLoading = false; +void initState(){ + final guardObserver = context.router.activeGuardObserver; + + guardObserver.addListener(() { + setState((){ + isLoading = guardObserver.guardInProgress; + }); + }); +} +``` + + +## Migrating to v6 + +In version 6.0 **AutoRoute** aims for less generated code for more flexibility and less generation time. + +#### 1. Instead of using `MaterialAutoRouter`, `CupertinoAutoRouter`, etc, we now only have one annotation for our router which is `@AutoRouterConfig()` and instead of passing our routes list to the annotation we now pass it to the overridable getter `routes` inside of the generated router class and for the default route type you can override `defaultRouteType` + +#### Before + +```dart +// @CupertinoAutoRouter +// @AdaptiveAutoRouter +// @CustomAutoRouter +@MaterialAutoRouter( + routes: [ + // routes go here + ], +) +class $AppRouter {} +``` + +#### After + + ```dart +@AutoRouterConfig() +class AppRouter extends $AppRouter { + + @override + RouteType get defaultRouteType => RouteType.material(); //.cupertino, .adaptive ..etc + + @override + List get routes => [ + // routes go here + ]; +} +``` + +#### 2. Passing page components as types is changed, now you'd annotate the target page with `@RoutePage()` annotation and pass the generated `result.page` to AutoRoute(): + +#### Before + +```dart +class ProductDetailsPage extends StatelessWidget {} +``` + +```dart +AutoRoute(page: ProductDetailsPage) // as Type +``` + +#### After + +```dart +@RoutePage() // Add this annotation to your routable pages +class ProductDetailsPage extends StatelessWidget {} +``` + +```dart +AutoRoute(page: ProductDetailsRoute.page) // ProductDetailsRoute is generated +``` + +#### 3. `EmptyRoutePage` no longer exists, instead you will now make your own empty pages by extending the `AutoRouter` widget + +#### Before + +```dart +AutoRoute(page: EmptyRoutePage, name: 'ProductsRouter') // as Type +``` + +#### After + +```dart +@RoutePage(name: 'ProductsRouter') +class ProductsRouterPage extends AutoRouter {} +``` + +```dart +AutoRoute(page: ProductsRouter.page) +``` + +#### 4. Passing route guards is also changed now, instead of passing guards as types you now pass instances. + +#### Before + +```dart +AutoRoute(page: ProfilePage, guards:[AuthGuard]) // as Type +``` + +#### After + +```dart +AutoRoute(page: ProfilePage, guards:[AuthGuard()]) // as Instance +``` + +## Examples + +coming soon + +### Support auto_route + +You can support auto_route by liking it on Pub and staring it on Github, sharing ideas on how we can enhance a certain functionality or by reporting any problems you encounter and of course buying a couple coffees will help speed up the development process \ No newline at end of file From 3fbb011e3faf5fcb185e471f549bd72ace402073 Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 13:43:38 +0300 Subject: [PATCH 05/13] update migration docs --- migrations/migrating_to_v9.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/migrations/migrating_to_v9.md b/migrations/migrating_to_v9.md index 6fc15da2..41d41507 100644 --- a/migrations/migrating_to_v9.md +++ b/migrations/migrating_to_v9.md @@ -71,10 +71,13 @@ class AppRouter extends $AppRouter implements AutoRouteGuard { ```dart @AutoRouterConfig() class AppRouter extends RootStackRouter{ + final authGuard = AuthGuard(); + @override late final List guards = [ - authGuard, /// guard instance + authGuard, ///add guard instance + /// /// or use a simple guard wrapper AutoRouteGuard.simple((resolver, router) { /// guard logic From 2d230561aa86a33608d4ac0a8c814742af1d6f09 Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 14:08:01 +0300 Subject: [PATCH 06/13] fix a bug when returning custom roue builder --- README.md | 5 +- auto_route/example/lib/web_demo/web_main.dart | 3 +- .../lib/src/route/auto_route_config.dart | 4 +- auto_route/lib/src/route/route_type.dart | 20 ++++-- .../lib/src/router/auto_route_page.dart | 65 ++++++------------- 5 files changed, 43 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 06a745e8..734b83ff 100644 --- a/README.md +++ b/README.md @@ -1332,11 +1332,12 @@ CustomRoute( You can use your own custom route by passing a `CustomRouteBuilder` function to `CustomRoute' and implement the builder function the same way we did with the TransitionsBuilder function, the most important part here is passing the page argument to our custom route. +make sure you pass the return type to your custom route builder function. ```dart CustomRoute( page: CustomPage, - customRouteBuilder: (BuildContext context, Widget child, CustomPage page) { - return PageRouteBuilder( + customRouteBuilder: (BuildContext context, Widget child, AutoRoutePage page) { + return PageRouteBuilder( fullscreenDialog: page.fullscreenDialog, // this is important settings: page, diff --git a/auto_route/example/lib/web_demo/web_main.dart b/auto_route/example/lib/web_demo/web_main.dart index 9fdead16..562db97f 100644 --- a/auto_route/example/lib/web_demo/web_main.dart +++ b/auto_route/example/lib/web_demo/web_main.dart @@ -1,4 +1,5 @@ import 'package:example/mobile/router/router.dart'; +import 'package:example/web_demo/router/web_router.dart'; import 'package:flutter/material.dart'; //ignore_for_file: public_member_api_docs @@ -21,7 +22,7 @@ class AppState extends State { setState(() {}); }); - late final _router = AppRouter(); + late final _router = WebAppRouter( authService); @override Widget build(BuildContext context) { return MaterialApp.router( diff --git a/auto_route/lib/src/route/auto_route_config.dart b/auto_route/lib/src/route/auto_route_config.dart index 8c05298f..52179d1e 100644 --- a/auto_route/lib/src/route/auto_route_config.dart +++ b/auto_route/lib/src/route/auto_route_config.dart @@ -386,7 +386,7 @@ class CustomRoute extends AutoRoute { super.initial, super.allowSnapshotting = true, RouteTransitionsBuilder? transitionsBuilder, - CustomRouteBuilder? customRouteBuilder, + CustomRouteBuilder? customRouteBuilder, int? durationInMilliseconds, int? reverseDurationInMilliseconds, bool opaque = true, @@ -395,7 +395,7 @@ class CustomRoute extends AutoRoute { super.restorationId, Color? barrierColor, }) : super._( - type: CustomRouteType( + type: RouteType.custom( transitionsBuilder: transitionsBuilder, customRouteBuilder: customRouteBuilder, durationInMilliseconds: durationInMilliseconds, diff --git a/auto_route/lib/src/route/route_type.dart b/auto_route/lib/src/route/route_type.dart index f307028b..834651a2 100644 --- a/auto_route/lib/src/route/route_type.dart +++ b/auto_route/lib/src/route/route_type.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; /// Signature for custom router builder used by /// [CustomRouteType] -typedef CustomRouteBuilder = Route Function( +typedef CustomRouteBuilder = Route Function( BuildContext context, Widget child, AutoRoutePage page, @@ -73,7 +73,7 @@ class AdaptiveRouteType extends RouteType { } /// Generates a route with user-defined transitions -class CustomRouteType extends RouteType { +class CustomRouteType extends RouteType { /// this builder function is passed to the transition builder /// function in [PageRouteBuilder] /// @@ -92,13 +92,23 @@ class CustomRouteType extends RouteType { /// /// I couldn't type this function from here but it should match /// typedef [CustomRouteBuilder] = Route Function(BuildContext context, CustomPage page); - /// you should only reference the function when passing it so - /// the generator can import it into the generated file /// /// this builder function accepts a BuildContext and a CustomPage /// that has all the other properties assigned to it /// so using them then is totally up to you. - final CustomRouteBuilder? customRouteBuilder; + /// + /// Make sure you pass the Return Type to the Route function + /// ex: + /// CustomRoute( + /// path: '/user/:userID', + /// page: UserRoute.page, + /// customRouteBuilder: (context, child, page) { + /// return PageRouteBuilder( + /// settings: page, + /// pageBuilder: (context, _, __) => child, + /// ); + /// }, + final CustomRouteBuilder? customRouteBuilder; /// route transition duration in milliseconds /// is passed to [PageRouteBuilder] diff --git a/auto_route/lib/src/router/auto_route_page.dart b/auto_route/lib/src/router/auto_route_page.dart index 0a1dce28..71a83529 100644 --- a/auto_route/lib/src/router/auto_route_page.dart +++ b/auto_route/lib/src/router/auto_route_page.dart @@ -38,9 +38,7 @@ class AutoRoutePage extends Page { /// The pop completer that's used in navigation actions /// e.g [StackRouter.push] /// it completes when the built route is popped - Future get popped => routeData.router.ignorePopCompleters - ? SynchronousFuture(null) - : _popCompleter.future; + Future get popped => routeData.router.ignorePopCompleters ? SynchronousFuture(null) : _popCompleter.future; /// The widget passed to the route Widget get child => _child; @@ -49,9 +47,7 @@ class AutoRoutePage extends Page { AutoRoutePage({ required this.routeData, required Widget child, - }) : _child = child is AutoRouteWrapper - ? WrappedRoute(child: child as AutoRouteWrapper) - : child, + }) : _child = child is AutoRouteWrapper ? WrappedRoute(child: child as AutoRouteWrapper) : child, super( restorationId: routeData.restorationId, name: routeData.name, @@ -87,14 +83,13 @@ class AutoRoutePage extends Page { } else if (type is CustomRouteType) { final result = buildPage(context); if (type.customRouteBuilder != null) { - return type.customRouteBuilder!(context, result, this) as Route; + return type.customRouteBuilder!.call(context, result, this); } return _CustomPageBasedPageRouteBuilder(page: this, routeType: type); } else if (type is AdaptiveRouteType) { if (kIsWeb) { return _NoAnimationPageRouteBuilder(page: this); - } else if ([TargetPlatform.macOS, TargetPlatform.iOS] - .contains(defaultTargetPlatform)) { + } else if ([TargetPlatform.macOS, TargetPlatform.iOS].contains(defaultTargetPlatform)) { return _PageBasedCupertinoPageRoute(page: this, title: title); } } @@ -110,8 +105,7 @@ class AutoRoutePage extends Page { } } -class _PageBasedMaterialPageRoute extends PageRoute - with MaterialRouteTransitionMixin { +class _PageBasedMaterialPageRoute extends PageRoute with MaterialRouteTransitionMixin { _PageBasedMaterialPageRoute({ required AutoRoutePage page, }) : super(settings: page); @@ -151,23 +145,17 @@ class _PageBasedMaterialPageRoute extends PageRoute String get debugLabel => '${super.debugLabel}(${_page.name})'; @override - bool canTransitionTo(TransitionRoute nextRoute) => - _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); } bool _canTransitionTo(TransitionRoute nextRoute) { - return (nextRoute is _CustomPageBasedPageRouteBuilder && - !nextRoute.fullscreenDialog || - nextRoute is MaterialRouteTransitionMixin && - !nextRoute.fullscreenDialog) || - (nextRoute is _NoAnimationPageRouteTransitionMixin && - !nextRoute.fullscreenDialog) || - (nextRoute is CupertinoRouteTransitionMixin && - !nextRoute.fullscreenDialog); + return (nextRoute is _CustomPageBasedPageRouteBuilder && !nextRoute.fullscreenDialog || + nextRoute is MaterialRouteTransitionMixin && !nextRoute.fullscreenDialog) || + (nextRoute is _NoAnimationPageRouteTransitionMixin && !nextRoute.fullscreenDialog) || + (nextRoute is CupertinoRouteTransitionMixin && !nextRoute.fullscreenDialog); } -class _CustomPageBasedPageRouteBuilder extends PageRoute - with _CustomPageRouteTransitionMixin { +class _CustomPageBasedPageRouteBuilder extends PageRoute with _CustomPageRouteTransitionMixin { _CustomPageBasedPageRouteBuilder({ required AutoRoutePage page, required this.routeType, @@ -192,12 +180,10 @@ class _CustomPageBasedPageRouteBuilder extends PageRoute String get debugLabel => '${super.debugLabel}(${_page.name})'; @override - bool canTransitionTo(TransitionRoute nextRoute) => - _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); } -class _NoAnimationPageRouteBuilder extends PageRoute - with _NoAnimationPageRouteTransitionMixin { +class _NoAnimationPageRouteBuilder extends PageRoute with _NoAnimationPageRouteTransitionMixin { _NoAnimationPageRouteBuilder({ required AutoRoutePage page, }) : super(settings: page); @@ -221,8 +207,7 @@ class _NoAnimationPageRouteBuilder extends PageRoute Duration get transitionDuration => Duration.zero; @override - bool canTransitionTo(TransitionRoute nextRoute) => - _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); } mixin _NoAnimationPageRouteTransitionMixin on PageRoute { @@ -244,8 +229,7 @@ mixin _NoAnimationPageRouteTransitionMixin on PageRoute { bool get opaque => _page.opaque; @override - bool canTransitionTo(TransitionRoute nextRoute) => - _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); @override Widget buildPage( @@ -293,8 +277,7 @@ mixin _CustomPageRouteTransitionMixin on PageRoute { bool get opaque => routeType.opaque; @override - bool canTransitionTo(TransitionRoute nextRoute) => - _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); @override Widget buildPage( @@ -310,26 +293,20 @@ mixin _CustomPageRouteTransitionMixin on PageRoute { } Widget _defaultTransitionsBuilder( - BuildContext context, - Animation animation, - Animation secondaryAnimation, - Widget child) { + BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { return child; } @override - Widget buildTransitions(BuildContext context, Animation animation, - Animation secondaryAnimation, Widget child) { - final transitionsBuilder = - routeType.transitionsBuilder ?? _defaultTransitionsBuilder; + Widget buildTransitions( + BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { + final transitionsBuilder = routeType.transitionsBuilder ?? _defaultTransitionsBuilder; return transitionsBuilder(context, animation, secondaryAnimation, child); } } class _PageBasedCupertinoPageRoute extends PageRoute - with - CupertinoRouteTransitionMixin, - CupertinoRouteTransitionOverrideMixin { + with CupertinoRouteTransitionMixin, CupertinoRouteTransitionOverrideMixin { _PageBasedCupertinoPageRoute({ required AutoRoutePage page, this.title, From 9982b5698a77d8624c5b1ec5115c8bf7d11509c9 Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 14:08:13 +0300 Subject: [PATCH 07/13] fix a bug when returning custom roue builder --- auto_route/example/lib/web_demo/web_main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/auto_route/example/lib/web_demo/web_main.dart b/auto_route/example/lib/web_demo/web_main.dart index 562db97f..a32d5e25 100644 --- a/auto_route/example/lib/web_demo/web_main.dart +++ b/auto_route/example/lib/web_demo/web_main.dart @@ -1,4 +1,3 @@ -import 'package:example/mobile/router/router.dart'; import 'package:example/web_demo/router/web_router.dart'; import 'package:flutter/material.dart'; From 5784058776a35db7bfdd526bef2457640f07c60c Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 15:19:02 +0300 Subject: [PATCH 08/13] fix a bug when returning custom roue builder --- .../lib/web_demo/router/web_router.dart | 3 + .../lib/web_demo/router/web_router.gr.dart | 411 ------------------ 2 files changed, 3 insertions(+), 411 deletions(-) delete mode 100644 auto_route/example/lib/web_demo/router/web_router.gr.dart diff --git a/auto_route/example/lib/web_demo/router/web_router.dart b/auto_route/example/lib/web_demo/router/web_router.dart index 651c130a..fa6afaf8 100644 --- a/auto_route/example/lib/web_demo/router/web_router.dart +++ b/auto_route/example/lib/web_demo/router/web_router.dart @@ -66,6 +66,8 @@ class WebAppRouter extends RootStackRouter { ]; } +typedef CallBackX = void Function(T x, E y, R z); + @RoutePage() class MainWebPage extends StatefulWidget { final VoidCallback? navigate, showUserPosts; @@ -74,6 +76,7 @@ class MainWebPage extends StatefulWidget { Key? key, this.navigate, this.showUserPosts, + CallBackX? callBackX, }) : super(key: key); @override diff --git a/auto_route/example/lib/web_demo/router/web_router.gr.dart b/auto_route/example/lib/web_demo/router/web_router.gr.dart deleted file mode 100644 index 22c2876d..00000000 --- a/auto_route/example/lib/web_demo/router/web_router.gr.dart +++ /dev/null @@ -1,411 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -// ************************************************************************** -// AutoRouterGenerator -// ************************************************************************** - -// ignore_for_file: type=lint -// coverage:ignore-file - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:auto_route/auto_route.dart' as _i4; -import 'package:example/web_demo/router/web_login_page.dart' as _i2; -import 'package:example/web_demo/router/web_router.dart' as _i1; -import 'package:example/web_demo/router/web_verify_page.dart' as _i3; -import 'package:flutter/foundation.dart' as _i5; -import 'package:flutter/material.dart' as _i6; - -/// generated route for -/// [_i1.MainWebPage] -class MainWebRoute extends _i4.PageRouteInfo { - MainWebRoute({ - _i5.Key? key, - void Function()? navigate, - void Function()? showUserPosts, - List<_i4.PageRouteInfo>? children, - }) : super( - MainWebRoute.name, - args: MainWebRouteArgs( - key: key, - navigate: navigate, - showUserPosts: showUserPosts, - ), - initialChildren: children, - ); - - static const String name = 'MainWebRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - final args = - data.argsAs(orElse: () => const MainWebRouteArgs()); - return _i1.MainWebPage( - key: args.key, - navigate: args.navigate, - showUserPosts: args.showUserPosts, - ); - }, - ); -} - -class MainWebRouteArgs { - const MainWebRouteArgs({ - this.key, - this.navigate, - this.showUserPosts, - }); - - final _i5.Key? key; - - final void Function()? navigate; - - final void Function()? showUserPosts; - - @override - String toString() { - return 'MainWebRouteArgs{key: $key, navigate: $navigate, showUserPosts: $showUserPosts}'; - } -} - -/// generated route for -/// [_i1.NotFoundScreen] -class NotFoundRoute extends _i4.PageRouteInfo { - const NotFoundRoute({List<_i4.PageRouteInfo>? children}) - : super( - NotFoundRoute.name, - initialChildren: children, - ); - - static const String name = 'NotFoundRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - return _i1.NotFoundScreen(); - }, - ); -} - -/// generated route for -/// [_i1.UserAllPostsPage] -class UserAllPostsRoute extends _i4.PageRouteInfo { - UserAllPostsRoute({ - _i5.Key? key, - void Function()? navigate, - List<_i4.PageRouteInfo>? children, - }) : super( - UserAllPostsRoute.name, - args: UserAllPostsRouteArgs( - key: key, - navigate: navigate, - ), - initialChildren: children, - ); - - static const String name = 'UserAllPostsRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - final args = data.argsAs( - orElse: () => const UserAllPostsRouteArgs()); - return _i1.UserAllPostsPage( - key: args.key, - navigate: args.navigate, - ); - }, - ); -} - -class UserAllPostsRouteArgs { - const UserAllPostsRouteArgs({ - this.key, - this.navigate, - }); - - final _i5.Key? key; - - final void Function()? navigate; - - @override - String toString() { - return 'UserAllPostsRouteArgs{key: $key, navigate: $navigate}'; - } -} - -/// generated route for -/// [_i1.UserFavoritePostsPage] -class UserFavoritePostsRoute extends _i4.PageRouteInfo { - const UserFavoritePostsRoute({List<_i4.PageRouteInfo>? children}) - : super( - UserFavoritePostsRoute.name, - initialChildren: children, - ); - - static const String name = 'UserFavoritePostsRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - return _i1.UserFavoritePostsPage(); - }, - ); -} - -/// generated route for -/// [_i1.UserPage] -class UserRoute extends _i4.PageRouteInfo { - UserRoute({ - _i5.Key? key, - int id = -1, - List? query, - String? fragment, - List<_i4.PageRouteInfo>? children, - }) : super( - UserRoute.name, - args: UserRouteArgs( - key: key, - id: id, - query: query, - fragment: fragment, - ), - rawPathParams: {'userID': id}, - rawQueryParams: {'query': query}, - fragment: fragment, - initialChildren: children, - ); - - static const String name = 'UserRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - final pathParams = data.inheritedPathParams; - final queryParams = data.queryParams; - final args = data.argsAs( - orElse: () => UserRouteArgs( - id: pathParams.getInt( - 'userID', - -1, - ), - query: queryParams.optList('query'), - fragment: data.fragment, - )); - return _i1.UserPage( - key: args.key, - id: args.id, - query: args.query, - fragment: args.fragment, - ); - }, - ); -} - -class UserRouteArgs { - const UserRouteArgs({ - this.key, - this.id = -1, - this.query, - this.fragment, - }); - - final _i5.Key? key; - - final int id; - - final List? query; - - final String? fragment; - - @override - String toString() { - return 'UserRouteArgs{key: $key, id: $id, query: $query, fragment: $fragment}'; - } -} - -/// generated route for -/// [_i1.UserPostsPage] -class UserPostsRoute extends _i4.PageRouteInfo { - UserPostsRoute({List<_i4.PageRouteInfo>? children}) - : super( - UserPostsRoute.name, - initialChildren: children, - ); - - static const String name = 'UserPostsRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - final pathParams = data.inheritedPathParams; - return _i1.UserPostsPage(id: pathParams.getInt('userID')); - }, - ); -} - -/// generated route for -/// [_i1.UserProfilePage] -class UserProfileRoute extends _i4.PageRouteInfo { - UserProfileRoute({ - _i5.Key? key, - void Function()? navigate, - int userId = -1, - int likes = 0, - List<_i4.PageRouteInfo>? children, - }) : super( - UserProfileRoute.name, - args: UserProfileRouteArgs( - key: key, - navigate: navigate, - userId: userId, - likes: likes, - ), - rawPathParams: {'userID': userId}, - rawQueryParams: {'likes': likes}, - initialChildren: children, - ); - - static const String name = 'UserProfileRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - final pathParams = data.inheritedPathParams; - final queryParams = data.queryParams; - final args = data.argsAs( - orElse: () => UserProfileRouteArgs( - userId: pathParams.getInt( - 'userID', - -1, - ), - likes: queryParams.getInt( - 'likes', - 0, - ), - )); - return _i1.UserProfilePage( - key: args.key, - navigate: args.navigate, - userId: args.userId, - likes: args.likes, - ); - }, - ); -} - -class UserProfileRouteArgs { - const UserProfileRouteArgs({ - this.key, - this.navigate, - this.userId = -1, - this.likes = 0, - }); - - final _i5.Key? key; - - final void Function()? navigate; - - final int userId; - - final int likes; - - @override - String toString() { - return 'UserProfileRouteArgs{key: $key, navigate: $navigate, userId: $userId, likes: $likes}'; - } -} - -/// generated route for -/// [_i2.WebLoginPage] -class WebLoginRoute extends _i4.PageRouteInfo { - WebLoginRoute({ - _i6.Key? key, - void Function(bool)? onResult, - List<_i4.PageRouteInfo>? children, - }) : super( - WebLoginRoute.name, - args: WebLoginRouteArgs( - key: key, - onResult: onResult, - ), - initialChildren: children, - ); - - static const String name = 'WebLoginRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - final args = data.argsAs( - orElse: () => const WebLoginRouteArgs()); - return _i2.WebLoginPage( - key: args.key, - onResult: args.onResult, - ); - }, - ); -} - -class WebLoginRouteArgs { - const WebLoginRouteArgs({ - this.key, - this.onResult, - }); - - final _i6.Key? key; - - final void Function(bool)? onResult; - - @override - String toString() { - return 'WebLoginRouteArgs{key: $key, onResult: $onResult}'; - } -} - -/// generated route for -/// [_i3.WebVerifyPage] -class WebVerifyRoute extends _i4.PageRouteInfo { - WebVerifyRoute({ - _i6.Key? key, - void Function(bool)? onResult, - List<_i4.PageRouteInfo>? children, - }) : super( - WebVerifyRoute.name, - args: WebVerifyRouteArgs( - key: key, - onResult: onResult, - ), - initialChildren: children, - ); - - static const String name = 'WebVerifyRoute'; - - static _i4.PageInfo page = _i4.PageInfo( - name, - builder: (data) { - final args = data.argsAs( - orElse: () => const WebVerifyRouteArgs()); - return _i3.WebVerifyPage( - key: args.key, - onResult: args.onResult, - ); - }, - ); -} - -class WebVerifyRouteArgs { - const WebVerifyRouteArgs({ - this.key, - this.onResult, - }); - - final _i6.Key? key; - - final void Function(bool)? onResult; - - @override - String toString() { - return 'WebVerifyRouteArgs{key: $key, onResult: $onResult}'; - } -} From b17e1047f1427d2341874a7d4c85f59331dbeaf2 Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 15:19:27 +0300 Subject: [PATCH 09/13] fix a bug when returning custom roue builder --- .../resolvers/route_parameter_resolver.dart | 2 +- .../lib/src/resolvers/type_resolver.dart | 37 ++++++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart b/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart index 9e95c812..4fc2f639 100644 --- a/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart @@ -21,7 +21,7 @@ class RouteParameterResolver { /// Resolves a ParameterElement into a consumable [ParamConfig] ParamConfig resolve(ParameterElement parameterElement) { final paramType = parameterElement.type; - if (paramType is FunctionType) { + if (paramType is FunctionType && paramType.alias == null) { return _resolveFunctionType(parameterElement); } var type = _typeResolver.resolveType(paramType); diff --git a/auto_route_generator/lib/src/resolvers/type_resolver.dart b/auto_route_generator/lib/src/resolvers/type_resolver.dart index b5329e58..bd182d32 100644 --- a/auto_route_generator/lib/src/resolvers/type_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/type_resolver.dart @@ -1,9 +1,12 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/nullability_suffix.dart' show NullabilitySuffix; -import 'package:analyzer/dart/element/type.dart' show DartType, ParameterizedType, RecordType; +import 'package:analyzer/dart/element/type.dart' + show DartType, ParameterizedType, RecordType; import 'package:auto_route_generator/src/models/resolved_type.dart'; import 'package:path/path.dart' as p; + +const _unPreferredImports = {'dart:ui'}; /// A Helper class that resolves types class TypeResolver { /// The list of resolved libraries in [BuildStep] @@ -21,16 +24,22 @@ class TypeResolver { if (libs.isEmpty || element?.source == null || _isCoreDartType(element!)) { return null; } + + final fallBackImports = {}; for (var lib in libs) { if (!_isCoreDartType(lib) && lib.exportNamespace.definedNames.values.contains(element)) { final uri = lib.source.uri; + if(_unPreferredImports.contains(uri.toString())){ + fallBackImports.add(uri.toString()); + continue; + } if (uri.scheme == 'asset') { return _assetToPackage(lib.source.uri); } return targetFile == null ? lib.identifier : _relative(uri, targetFile!); } } - return null; + return fallBackImports.firstOrNull; } String _assetToPackage(Uri uri) { @@ -114,19 +123,29 @@ class TypeResolver { /// Resolves the given [type] to a [ResolvedType] ResolvedType resolveType(DartType type) { - if (type is RecordType) { + final effectiveElement = type.alias?.element ?? type.element; + final import = resolveImport(effectiveElement); + final typeArgs = []; + final alias = type.alias; + if(alias != null) { + typeArgs.addAll(alias.typeArguments.map(resolveType)); + }else { + typeArgs.addAll(_resolveTypeArguments(type)); + } + if (type is RecordType && type.alias == null) { return ResolvedType.record( - name: type.element?.name ?? 'void', - import: resolveImport(type.element), + name: effectiveElement?.displayName ?? 'void', + import: import, isNullable: type.nullabilitySuffix == NullabilitySuffix.question, - typeArguments: _resolveTypeArguments(type), + typeArguments: typeArgs, ); } + return ResolvedType( - name: type.element?.name ?? type.getDisplayString(withNullability: false), + name: effectiveElement?.displayName ?? type.getDisplayString(withNullability: false), isNullable: type.nullabilitySuffix == NullabilitySuffix.question, - import: resolveImport(type.element), - typeArguments: _resolveTypeArguments(type), + import: import, + typeArguments: typeArgs, ); } } From a90a0fe85b66f3a59076ef0518c9a39490158a57 Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 15:19:58 +0300 Subject: [PATCH 10/13] fix a bug when returning custom roue builder --- .../lib/web_demo/router/web_router.dart | 2 - .../lib/web_demo/router/web_router.gr.dart | 411 ++++++++++++++++++ 2 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 auto_route/example/lib/web_demo/router/web_router.gr.dart diff --git a/auto_route/example/lib/web_demo/router/web_router.dart b/auto_route/example/lib/web_demo/router/web_router.dart index fa6afaf8..2a4c361d 100644 --- a/auto_route/example/lib/web_demo/router/web_router.dart +++ b/auto_route/example/lib/web_demo/router/web_router.dart @@ -66,7 +66,6 @@ class WebAppRouter extends RootStackRouter { ]; } -typedef CallBackX = void Function(T x, E y, R z); @RoutePage() class MainWebPage extends StatefulWidget { @@ -76,7 +75,6 @@ class MainWebPage extends StatefulWidget { Key? key, this.navigate, this.showUserPosts, - CallBackX? callBackX, }) : super(key: key); @override diff --git a/auto_route/example/lib/web_demo/router/web_router.gr.dart b/auto_route/example/lib/web_demo/router/web_router.gr.dart new file mode 100644 index 00000000..0980aa32 --- /dev/null +++ b/auto_route/example/lib/web_demo/router/web_router.gr.dart @@ -0,0 +1,411 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// AutoRouterGenerator +// ************************************************************************** + +// ignore_for_file: type=lint +// coverage:ignore-file + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:auto_route/auto_route.dart' as _i4; +import 'package:example/web_demo/router/web_login_page.dart' as _i2; +import 'package:example/web_demo/router/web_router.dart' as _i1; +import 'package:example/web_demo/router/web_verify_page.dart' as _i3; +import 'package:flutter/foundation.dart' as _i5; +import 'package:flutter/material.dart' as _i6; + +/// generated route for +/// [_i1.MainWebPage] +class MainWebRoute extends _i4.PageRouteInfo { + MainWebRoute({ + _i5.Key? key, + _i5.VoidCallback? navigate, + _i5.VoidCallback? showUserPosts, + List<_i4.PageRouteInfo>? children, + }) : super( + MainWebRoute.name, + args: MainWebRouteArgs( + key: key, + navigate: navigate, + showUserPosts: showUserPosts, + ), + initialChildren: children, + ); + + static const String name = 'MainWebRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = + data.argsAs(orElse: () => const MainWebRouteArgs()); + return _i1.MainWebPage( + key: args.key, + navigate: args.navigate, + showUserPosts: args.showUserPosts, + ); + }, + ); +} + +class MainWebRouteArgs { + const MainWebRouteArgs({ + this.key, + this.navigate, + this.showUserPosts, + }); + + final _i5.Key? key; + + final _i5.VoidCallback? navigate; + + final _i5.VoidCallback? showUserPosts; + + @override + String toString() { + return 'MainWebRouteArgs{key: $key, navigate: $navigate, showUserPosts: $showUserPosts}'; + } +} + +/// generated route for +/// [_i1.NotFoundScreen] +class NotFoundRoute extends _i4.PageRouteInfo { + const NotFoundRoute({List<_i4.PageRouteInfo>? children}) + : super( + NotFoundRoute.name, + initialChildren: children, + ); + + static const String name = 'NotFoundRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + return _i1.NotFoundScreen(); + }, + ); +} + +/// generated route for +/// [_i1.UserAllPostsPage] +class UserAllPostsRoute extends _i4.PageRouteInfo { + UserAllPostsRoute({ + _i5.Key? key, + _i5.VoidCallback? navigate, + List<_i4.PageRouteInfo>? children, + }) : super( + UserAllPostsRoute.name, + args: UserAllPostsRouteArgs( + key: key, + navigate: navigate, + ), + initialChildren: children, + ); + + static const String name = 'UserAllPostsRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const UserAllPostsRouteArgs()); + return _i1.UserAllPostsPage( + key: args.key, + navigate: args.navigate, + ); + }, + ); +} + +class UserAllPostsRouteArgs { + const UserAllPostsRouteArgs({ + this.key, + this.navigate, + }); + + final _i5.Key? key; + + final _i5.VoidCallback? navigate; + + @override + String toString() { + return 'UserAllPostsRouteArgs{key: $key, navigate: $navigate}'; + } +} + +/// generated route for +/// [_i1.UserFavoritePostsPage] +class UserFavoritePostsRoute extends _i4.PageRouteInfo { + const UserFavoritePostsRoute({List<_i4.PageRouteInfo>? children}) + : super( + UserFavoritePostsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserFavoritePostsRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + return _i1.UserFavoritePostsPage(); + }, + ); +} + +/// generated route for +/// [_i1.UserPage] +class UserRoute extends _i4.PageRouteInfo { + UserRoute({ + _i5.Key? key, + int id = -1, + List? query, + String? fragment, + List<_i4.PageRouteInfo>? children, + }) : super( + UserRoute.name, + args: UserRouteArgs( + key: key, + id: id, + query: query, + fragment: fragment, + ), + rawPathParams: {'userID': id}, + rawQueryParams: {'query': query}, + fragment: fragment, + initialChildren: children, + ); + + static const String name = 'UserRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final queryParams = data.queryParams; + final args = data.argsAs( + orElse: () => UserRouteArgs( + id: pathParams.getInt( + 'userID', + -1, + ), + query: queryParams.optList('query'), + fragment: data.fragment, + )); + return _i1.UserPage( + key: args.key, + id: args.id, + query: args.query, + fragment: args.fragment, + ); + }, + ); +} + +class UserRouteArgs { + const UserRouteArgs({ + this.key, + this.id = -1, + this.query, + this.fragment, + }); + + final _i5.Key? key; + + final int id; + + final List? query; + + final String? fragment; + + @override + String toString() { + return 'UserRouteArgs{key: $key, id: $id, query: $query, fragment: $fragment}'; + } +} + +/// generated route for +/// [_i1.UserPostsPage] +class UserPostsRoute extends _i4.PageRouteInfo { + UserPostsRoute({List<_i4.PageRouteInfo>? children}) + : super( + UserPostsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserPostsRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + return _i1.UserPostsPage(id: pathParams.getInt('userID')); + }, + ); +} + +/// generated route for +/// [_i1.UserProfilePage] +class UserProfileRoute extends _i4.PageRouteInfo { + UserProfileRoute({ + _i5.Key? key, + _i5.VoidCallback? navigate, + int userId = -1, + int likes = 0, + List<_i4.PageRouteInfo>? children, + }) : super( + UserProfileRoute.name, + args: UserProfileRouteArgs( + key: key, + navigate: navigate, + userId: userId, + likes: likes, + ), + rawPathParams: {'userID': userId}, + rawQueryParams: {'likes': likes}, + initialChildren: children, + ); + + static const String name = 'UserProfileRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final queryParams = data.queryParams; + final args = data.argsAs( + orElse: () => UserProfileRouteArgs( + userId: pathParams.getInt( + 'userID', + -1, + ), + likes: queryParams.getInt( + 'likes', + 0, + ), + )); + return _i1.UserProfilePage( + key: args.key, + navigate: args.navigate, + userId: args.userId, + likes: args.likes, + ); + }, + ); +} + +class UserProfileRouteArgs { + const UserProfileRouteArgs({ + this.key, + this.navigate, + this.userId = -1, + this.likes = 0, + }); + + final _i5.Key? key; + + final _i5.VoidCallback? navigate; + + final int userId; + + final int likes; + + @override + String toString() { + return 'UserProfileRouteArgs{key: $key, navigate: $navigate, userId: $userId, likes: $likes}'; + } +} + +/// generated route for +/// [_i2.WebLoginPage] +class WebLoginRoute extends _i4.PageRouteInfo { + WebLoginRoute({ + _i6.Key? key, + _i6.ValueChanged? onResult, + List<_i4.PageRouteInfo>? children, + }) : super( + WebLoginRoute.name, + args: WebLoginRouteArgs( + key: key, + onResult: onResult, + ), + initialChildren: children, + ); + + static const String name = 'WebLoginRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const WebLoginRouteArgs()); + return _i2.WebLoginPage( + key: args.key, + onResult: args.onResult, + ); + }, + ); +} + +class WebLoginRouteArgs { + const WebLoginRouteArgs({ + this.key, + this.onResult, + }); + + final _i6.Key? key; + + final _i6.ValueChanged? onResult; + + @override + String toString() { + return 'WebLoginRouteArgs{key: $key, onResult: $onResult}'; + } +} + +/// generated route for +/// [_i3.WebVerifyPage] +class WebVerifyRoute extends _i4.PageRouteInfo { + WebVerifyRoute({ + _i6.Key? key, + _i6.ValueChanged? onResult, + List<_i4.PageRouteInfo>? children, + }) : super( + WebVerifyRoute.name, + args: WebVerifyRouteArgs( + key: key, + onResult: onResult, + ), + initialChildren: children, + ); + + static const String name = 'WebVerifyRoute'; + + static _i4.PageInfo page = _i4.PageInfo( + name, + builder: (data) { + final args = data.argsAs( + orElse: () => const WebVerifyRouteArgs()); + return _i3.WebVerifyPage( + key: args.key, + onResult: args.onResult, + ); + }, + ); +} + +class WebVerifyRouteArgs { + const WebVerifyRouteArgs({ + this.key, + this.onResult, + }); + + final _i6.Key? key; + + final _i6.ValueChanged? onResult; + + @override + String toString() { + return 'WebVerifyRouteArgs{key: $key, onResult: $onResult}'; + } +} From 01cd3ba21872f64fcc354ddb5e7e5ed4674a495a Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 15:48:53 +0300 Subject: [PATCH 11/13] prepare merge --- README.md | 31 +++++++++++++++++++++++++++++- art/auto_route_logo.png | Bin 0 -> 17946 bytes auto_route/CHANGELOG.md | 20 +++++++++++++++++++ auto_route/pubspec.yaml | 13 ++++++++++--- auto_route_generator/CHANGELOG.md | 21 ++++++++++++++++++++ auto_route_generator/pubspec.yaml | 4 ++-- 6 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 art/auto_route_logo.png diff --git a/README.md b/README.md index 734b83ff..7ec501de 100644 --- a/README.md +++ b/README.md @@ -400,7 +400,6 @@ class DashboardPage extends StatelessWidget { } } ``` - **Note** NavLink is just a button that calls router.push(destination). Now if we navigate to `/dashboard/users`, we will be taken to the `DashboardPage` and the `UsersPage` will be shown inside of it. What if want to show one of the child pages at `/dashboard`? We can simply do that by giving the child routes an empty path `''` to make initial or by setting initial to true. @@ -416,6 +415,36 @@ AutoRoute( ) ``` +#### Creating Empty Shell routes +Empty shell routes build a screen that contain the `AutoRouter` widget, which is used to render nested routes. +So you can build the widget your self like follows: +```dart +@RoutePage() +class MyShellPage extends StatelessWidget { + const MyShellPage({Key? key}) : super(key: key); + @override + Widget build(BuildContext context) { + /// you can wrap the AutoRouter with any widget you want + return AutoRouter(); + } +} +``` +You can shorten the code above a bit by directly extending the `AutoRouter` Widget. +```dart +@RoutePage() +class MyShellPage extends AutoRouter { + const MyShellPage({Key? key}) : super(key: key); +} +``` + +finally you can create a shell route without code generation using the `EmptyShellRoute` helper + + ```dart + final BooksTab = EmptyShellRoute('BooksTab'); + context.push(BooksTab()); + ``` + + or by using a `RedirectRoute` ```dart diff --git a/art/auto_route_logo.png b/art/auto_route_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..905ef315d03ea096d8746138d980c3edfa4df70d GIT binary patch literal 17946 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 is no longer needed. you + just provide the type as you push the page. +- **BREAKING CHANGE**: Providing a global route is now done by overriding the `guards` property + inside the router. implementing AutoRouteGuard is no longer supported. +- **BREAKING CHANGE**: `AutoRouterConfig.module` is removed as it's no longer needed. `PageRouteInfos` are now self-contained. +- + For more info read the complete migration guide + [Migrating to v9](https://github.com/Milad-Akarie/auto_route_library/blob/master/migrations/migrating_to_v9.md) + +- **FIX**: Fix Aliased types are not generated correctly. +- **FEAT**: You can now create empty shell routes like follows: + ```dart + final BooksTab = EmptyShellRoute('BooksTab'); + context.push(BooksTab()); + ``` + ## 8.3.0 - **FEAT**: add url#fragment support. diff --git a/auto_route/pubspec.yaml b/auto_route/pubspec.yaml index 1c351acd..c5f27cd6 100644 --- a/auto_route/pubspec.yaml +++ b/auto_route/pubspec.yaml @@ -1,7 +1,14 @@ name: auto_route description: AutoRoute is a declarative routing solution, where everything needed for navigation is automatically generated for you. -version: 8.3.0 +version: 9.0.0 homepage: https://github.com/Milad-Akarie/auto_route_library +screenshots: + - description: 'Auto Route Logo' + path: art/auto_route_logo.png +topics: + - Navigation + - Router + - Flutter Routes environment: sdk: ">=3.0.0 <4.0.0" @@ -11,7 +18,7 @@ dependencies: flutter: sdk: flutter path: ^1.9.0 - web: ^0.5.1 + web: ^1.0.0 collection: ^1.18.0 meta: ^1.12.0 @@ -21,7 +28,7 @@ dependencies: dev_dependencies: build_runner: mockito: ^5.4.4 - auto_route_generator: ^8.1.0 + auto_route_generator: ^9.0.0 flutter_test: sdk: flutter flutter_lints: ^4.0.0 diff --git a/auto_route_generator/CHANGELOG.md b/auto_route_generator/CHANGELOG.md index c0856dcd..9d46096c 100644 --- a/auto_route_generator/CHANGELOG.md +++ b/auto_route_generator/CHANGELOG.md @@ -1,3 +1,24 @@ +## 9.0.0 [Breaking Changes] + +- **BREAKING CHANGE**: No Router class will be generated anymore. Instead, you + extend `RootStackRouter` from the `auto_route` package. +- **BREAKING CHANGE**: Providing return types inside `@RoutePage()` is no longer needed. you + just provide the type as you push the page. +- **BREAKING CHANGE**: Providing a global route is now done by overriding the `guards` property + inside the router. implementing AutoRouteGuard is no longer supported. +- **BREAKING CHANGE**: `AutoRouterConfig.module` is removed as it's no longer needed. `PageRouteInfos` are now self-contained. +- +For more info read the complete migration guide +[Migrating to v9](https://github.com/Milad-Akarie/auto_route_library/blob/master/migrations/migrating_to_v9.md) + +- **FIX**: Fix Aliased types are not generated correctly. +- **FEAT**: You can now create empty shell routes like follows: + ```dart + final BooksTab = EmptyShellRoute('BooksTab'); + context.push(BooksTab()); + ``` + + ## 8.1.0 - **FEAT**: add url#fragment support. - **CHORE**: update auto_route_generator dependencies diff --git a/auto_route_generator/pubspec.yaml b/auto_route_generator/pubspec.yaml index 65c92933..61aa4e9e 100644 --- a/auto_route_generator/pubspec.yaml +++ b/auto_route_generator/pubspec.yaml @@ -1,6 +1,6 @@ name: auto_route_generator description: AutoRoute is a declarative routing solution, where everything needed for navigation is automatically generated for you. -version: 8.1.0 +version: 9.0.0 homepage: https://github.com/Milad-Akarie/auto_route_library environment: sdk: ">=3.3.0 <4.0.0" @@ -19,7 +19,7 @@ dependencies: args: ^2.5.0 glob: ^2.1.2 package_config: ^2.1.0 - auto_route: ^8.3.0 + auto_route: ^9.0.0 From 759508b2bdcb5afcc8ca30844135d166f4b91d3c Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 15:49:43 +0300 Subject: [PATCH 12/13] prepare merge --- auto_route/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto_route/pubspec.yaml b/auto_route/pubspec.yaml index c5f27cd6..9a94b941 100644 --- a/auto_route/pubspec.yaml +++ b/auto_route/pubspec.yaml @@ -4,7 +4,7 @@ version: 9.0.0 homepage: https://github.com/Milad-Akarie/auto_route_library screenshots: - description: 'Auto Route Logo' - path: art/auto_route_logo.png + path: ../art/auto_route_logo.png topics: - Navigation - Router From f4622ddab8346268f250fd54874da49486b4384a Mon Sep 17 00:00:00 2001 From: milad Date: Tue, 30 Jul 2024 15:51:11 +0300 Subject: [PATCH 13/13] format code --- .../example/lib/mobile/router/router.dart | 3 - .../lib/web_demo/router/web_router.dart | 1 - auto_route/example/lib/web_demo/web_main.dart | 2 +- auto_route/lib/src/route/page_route_info.dart | 2 - .../lib/src/router/auto_route_page.dart | 63 +++++++++++----- .../custom_cupertino_transitions_builder.dart | 5 +- .../builders/auto_router_builder_base.dart | 23 ++++-- .../lib/src/builders/cache_aware_builder.dart | 3 +- .../deferred_pages_allocator.dart | 12 ++- .../lib/src/code_builder/library_builder.dart | 16 ++-- .../src/code_builder/route_info_builder.dart | 75 +++++++++++++------ .../lib/src/models/resolved_type.dart | 20 +++-- .../lib/src/models/route_config.dart | 18 +++-- .../src/models/route_parameter_config.dart | 4 +- .../lib/src/models/router_config.dart | 3 - .../src/resolvers/route_config_resolver.dart | 10 ++- .../resolvers/route_parameter_resolver.dart | 11 ++- .../src/resolvers/router_config_resolver.dart | 2 - .../lib/src/resolvers/type_resolver.dart | 41 ++++++---- 19 files changed, 201 insertions(+), 113 deletions(-) diff --git a/auto_route/example/lib/mobile/router/router.dart b/auto_route/example/lib/mobile/router/router.dart index d3495881..23e19069 100644 --- a/auto_route/example/lib/mobile/router/router.dart +++ b/auto_route/example/lib/mobile/router/router.dart @@ -3,7 +3,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:example/mobile/router/router.gr.dart'; import 'package:example/mobile/screens/profile/routes.dart'; - @AutoRouterConfig(generateForDir: ['lib/mobile']) class AppRouter extends RootStackRouter { @override @@ -45,5 +44,3 @@ class AppRouter extends RootStackRouter { final BooksTab = EmptyShellRoute('BooksTab'); final ProfileTab = EmptyShellRoute('ProfileTab'); - - diff --git a/auto_route/example/lib/web_demo/router/web_router.dart b/auto_route/example/lib/web_demo/router/web_router.dart index 2a4c361d..651c130a 100644 --- a/auto_route/example/lib/web_demo/router/web_router.dart +++ b/auto_route/example/lib/web_demo/router/web_router.dart @@ -66,7 +66,6 @@ class WebAppRouter extends RootStackRouter { ]; } - @RoutePage() class MainWebPage extends StatefulWidget { final VoidCallback? navigate, showUserPosts; diff --git a/auto_route/example/lib/web_demo/web_main.dart b/auto_route/example/lib/web_demo/web_main.dart index a32d5e25..61996f22 100644 --- a/auto_route/example/lib/web_demo/web_main.dart +++ b/auto_route/example/lib/web_demo/web_main.dart @@ -21,7 +21,7 @@ class AppState extends State { setState(() {}); }); - late final _router = WebAppRouter( authService); + late final _router = WebAppRouter(authService); @override Widget build(BuildContext context) { return MaterialApp.router( diff --git a/auto_route/lib/src/route/page_route_info.dart b/auto_route/lib/src/route/page_route_info.dart index 54e77da6..695e6502 100644 --- a/auto_route/lib/src/route/page_route_info.dart +++ b/auto_route/lib/src/route/page_route_info.dart @@ -195,11 +195,9 @@ class PageRouteInfo { const ListEquality().hash(initialChildren); } - /// A proxy Route page that provides a way to create a [PageRouteInfo] /// without the need for creating a new Page Widget class EmptyShellRoute { - /// Page name final String name; diff --git a/auto_route/lib/src/router/auto_route_page.dart b/auto_route/lib/src/router/auto_route_page.dart index 71a83529..76551030 100644 --- a/auto_route/lib/src/router/auto_route_page.dart +++ b/auto_route/lib/src/router/auto_route_page.dart @@ -38,7 +38,9 @@ class AutoRoutePage extends Page { /// The pop completer that's used in navigation actions /// e.g [StackRouter.push] /// it completes when the built route is popped - Future get popped => routeData.router.ignorePopCompleters ? SynchronousFuture(null) : _popCompleter.future; + Future get popped => routeData.router.ignorePopCompleters + ? SynchronousFuture(null) + : _popCompleter.future; /// The widget passed to the route Widget get child => _child; @@ -47,7 +49,9 @@ class AutoRoutePage extends Page { AutoRoutePage({ required this.routeData, required Widget child, - }) : _child = child is AutoRouteWrapper ? WrappedRoute(child: child as AutoRouteWrapper) : child, + }) : _child = child is AutoRouteWrapper + ? WrappedRoute(child: child as AutoRouteWrapper) + : child, super( restorationId: routeData.restorationId, name: routeData.name, @@ -89,7 +93,8 @@ class AutoRoutePage extends Page { } else if (type is AdaptiveRouteType) { if (kIsWeb) { return _NoAnimationPageRouteBuilder(page: this); - } else if ([TargetPlatform.macOS, TargetPlatform.iOS].contains(defaultTargetPlatform)) { + } else if ([TargetPlatform.macOS, TargetPlatform.iOS] + .contains(defaultTargetPlatform)) { return _PageBasedCupertinoPageRoute(page: this, title: title); } } @@ -105,7 +110,8 @@ class AutoRoutePage extends Page { } } -class _PageBasedMaterialPageRoute extends PageRoute with MaterialRouteTransitionMixin { +class _PageBasedMaterialPageRoute extends PageRoute + with MaterialRouteTransitionMixin { _PageBasedMaterialPageRoute({ required AutoRoutePage page, }) : super(settings: page); @@ -145,17 +151,23 @@ class _PageBasedMaterialPageRoute extends PageRoute with MaterialRouteTran String get debugLabel => '${super.debugLabel}(${_page.name})'; @override - bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => + _canTransitionTo(nextRoute); } bool _canTransitionTo(TransitionRoute nextRoute) { - return (nextRoute is _CustomPageBasedPageRouteBuilder && !nextRoute.fullscreenDialog || - nextRoute is MaterialRouteTransitionMixin && !nextRoute.fullscreenDialog) || - (nextRoute is _NoAnimationPageRouteTransitionMixin && !nextRoute.fullscreenDialog) || - (nextRoute is CupertinoRouteTransitionMixin && !nextRoute.fullscreenDialog); + return (nextRoute is _CustomPageBasedPageRouteBuilder && + !nextRoute.fullscreenDialog || + nextRoute is MaterialRouteTransitionMixin && + !nextRoute.fullscreenDialog) || + (nextRoute is _NoAnimationPageRouteTransitionMixin && + !nextRoute.fullscreenDialog) || + (nextRoute is CupertinoRouteTransitionMixin && + !nextRoute.fullscreenDialog); } -class _CustomPageBasedPageRouteBuilder extends PageRoute with _CustomPageRouteTransitionMixin { +class _CustomPageBasedPageRouteBuilder extends PageRoute + with _CustomPageRouteTransitionMixin { _CustomPageBasedPageRouteBuilder({ required AutoRoutePage page, required this.routeType, @@ -180,10 +192,12 @@ class _CustomPageBasedPageRouteBuilder extends PageRoute with _CustomPageR String get debugLabel => '${super.debugLabel}(${_page.name})'; @override - bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => + _canTransitionTo(nextRoute); } -class _NoAnimationPageRouteBuilder extends PageRoute with _NoAnimationPageRouteTransitionMixin { +class _NoAnimationPageRouteBuilder extends PageRoute + with _NoAnimationPageRouteTransitionMixin { _NoAnimationPageRouteBuilder({ required AutoRoutePage page, }) : super(settings: page); @@ -207,7 +221,8 @@ class _NoAnimationPageRouteBuilder extends PageRoute with _NoAnimationPage Duration get transitionDuration => Duration.zero; @override - bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => + _canTransitionTo(nextRoute); } mixin _NoAnimationPageRouteTransitionMixin on PageRoute { @@ -229,7 +244,8 @@ mixin _NoAnimationPageRouteTransitionMixin on PageRoute { bool get opaque => _page.opaque; @override - bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => + _canTransitionTo(nextRoute); @override Widget buildPage( @@ -277,7 +293,8 @@ mixin _CustomPageRouteTransitionMixin on PageRoute { bool get opaque => routeType.opaque; @override - bool canTransitionTo(TransitionRoute nextRoute) => _canTransitionTo(nextRoute); + bool canTransitionTo(TransitionRoute nextRoute) => + _canTransitionTo(nextRoute); @override Widget buildPage( @@ -293,20 +310,26 @@ mixin _CustomPageRouteTransitionMixin on PageRoute { } Widget _defaultTransitionsBuilder( - BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child) { return child; } @override - Widget buildTransitions( - BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { - final transitionsBuilder = routeType.transitionsBuilder ?? _defaultTransitionsBuilder; + Widget buildTransitions(BuildContext context, Animation animation, + Animation secondaryAnimation, Widget child) { + final transitionsBuilder = + routeType.transitionsBuilder ?? _defaultTransitionsBuilder; return transitionsBuilder(context, animation, secondaryAnimation, child); } } class _PageBasedCupertinoPageRoute extends PageRoute - with CupertinoRouteTransitionMixin, CupertinoRouteTransitionOverrideMixin { + with + CupertinoRouteTransitionMixin, + CupertinoRouteTransitionOverrideMixin { _PageBasedCupertinoPageRoute({ required AutoRoutePage page, this.title, diff --git a/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart b/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart index b5461f3f..bcbd7132 100644 --- a/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart +++ b/auto_route/lib/src/router/widgets/custom_cupertino_transitions_builder.dart @@ -503,9 +503,8 @@ class _CupertinoEdgeShadowDecoration extends Decoration { assert(bColors != null || aColors != null); // If it ever becomes necessary, we could allow decorations with different // length' here, similarly to how it is handled in [LinearGradient.lerp]. - assert(bColors == null || - aColors == null || - aColors.length == bColors.length); + assert( + bColors == null || aColors == null || aColors.length == bColors.length); return _CupertinoEdgeShadowDecoration._( [ for (int i = 0; i < bColors!.length; i += 1) diff --git a/auto_route_generator/lib/src/builders/auto_router_builder_base.dart b/auto_route_generator/lib/src/builders/auto_router_builder_base.dart index efb54cda..181b01b6 100644 --- a/auto_route_generator/lib/src/builders/auto_router_builder_base.dart +++ b/auto_route_generator/lib/src/builders/auto_router_builder_base.dart @@ -50,11 +50,15 @@ abstract class AutoRouterBuilderBase extends CacheAwareBuilder { for (final clazz in unit.declarations .whereType() .where((e) => e.metadata.any((e) => e.name.name == annotationName))) { - final routerAnnotation = clazz.metadata.firstWhere((e) => e.name.name == annotationName); - final partDirectives = - unit.directives.whereType().fold(0, (acc, a) => acc ^ a.toSource().hashCode); - calculatedHash = - calculatedHash ^ clazz.name.toString().hashCode ^ routerAnnotation.toSource().hashCode ^ partDirectives; + final routerAnnotation = + clazz.metadata.firstWhere((e) => e.name.name == annotationName); + final partDirectives = unit.directives + .whereType() + .fold(0, (acc, a) => acc ^ a.toSource().hashCode); + calculatedHash = calculatedHash ^ + clazz.name.toString().hashCode ^ + routerAnnotation.toSource().hashCode ^ + partDirectives; } return calculatedHash; } @@ -68,7 +72,8 @@ abstract class AutoRouterBuilderBase extends CacheAwareBuilder { } @override - Future onGenerateContent(BuildStep buildStep, RouterConfig item) async { + Future onGenerateContent( + BuildStep buildStep, RouterConfig item) async { final generateForDir = item.generateForDir; final generatedResults = []; final routes = []; @@ -103,7 +108,8 @@ abstract class AutoRouterBuilderBase extends CacheAwareBuilder { } @override - Future onResolve(LibraryReader library, BuildStep buildStep, int stepHash) async { + Future onResolve( + LibraryReader library, BuildStep buildStep, int stepHash) async { final annotatedElements = library.annotatedWith(_typeChecker); if (annotatedElements.isEmpty) return null; final element = annotatedElements.first.element; @@ -129,7 +135,8 @@ abstract class AutoRouterBuilderBase extends CacheAwareBuilder { return router; } - void _writeRouterFile(BuildStep buildStep, RouterConfig router, {bool toCache = false}) { + void _writeRouterFile(BuildStep buildStep, RouterConfig router, + {bool toCache = false}) { final routerFile = _buildRouterFile(buildStep, toCache: toCache); if (!routerFile.existsSync()) { routerFile.createSync(recursive: true); diff --git a/auto_route_generator/lib/src/builders/cache_aware_builder.dart b/auto_route_generator/lib/src/builders/cache_aware_builder.dart index e02017b0..3c84bc67 100644 --- a/auto_route_generator/lib/src/builders/cache_aware_builder.dart +++ b/auto_route_generator/lib/src/builders/cache_aware_builder.dart @@ -22,7 +22,8 @@ abstract class CacheAwareBuilder extends Builder { bool get cacheEnabled; /// Custom ignore for file rules passed from the options - Set get ignoreForFile => options?.config['ignore_for_file']?.cast()?.toSet() ?? {}; + Set get ignoreForFile => + options?.config['ignore_for_file']?.cast()?.toSet() ?? {}; @override final Map> buildExtensions; diff --git a/auto_route_generator/lib/src/code_builder/deferred_pages_allocator.dart b/auto_route_generator/lib/src/code_builder/deferred_pages_allocator.dart index da174f00..64084d94 100644 --- a/auto_route_generator/lib/src/code_builder/deferred_pages_allocator.dart +++ b/auto_route_generator/lib/src/code_builder/deferred_pages_allocator.dart @@ -33,9 +33,11 @@ class DeferredPagesAllocator implements Allocator { Iterable get imports => _imports.keys.map( (importPath) { if (routes.isDeferred(importPath, defaultDeferredLoading)) { - return Directive.importDeferredAs(importPath, '_i${_imports[importPath]}'); + return Directive.importDeferredAs( + importPath, '_i${_imports[importPath]}'); } else { - return Directive.import(importPath, as: '_i${_imports[importPath]}'); + return Directive.import(importPath, + as: '_i${_imports[importPath]}'); } }, ); @@ -43,10 +45,12 @@ class DeferredPagesAllocator implements Allocator { extension _RouteConfigList on List { bool isDeferred(String importPath, bool defaultDeferredLoading) { - return mapRouteToDeferredType(importPath, defaultDeferredLoading) == _DeferredStatus.Deferred; + return mapRouteToDeferredType(importPath, defaultDeferredLoading) == + _DeferredStatus.Deferred; } - _DeferredStatus mapRouteToDeferredType(String importPath, bool defaultDeferredLoading) { + _DeferredStatus mapRouteToDeferredType( + String importPath, bool defaultDeferredLoading) { for (RouteConfig routeConfig in this) { if (routeConfig.pageType?.import == importPath) { return (routeConfig.deferredLoading ?? defaultDeferredLoading) diff --git a/auto_route_generator/lib/src/code_builder/library_builder.dart b/auto_route_generator/lib/src/code_builder/library_builder.dart index 54add903..7cb9230e 100644 --- a/auto_route_generator/lib/src/code_builder/library_builder.dart +++ b/auto_route_generator/lib/src/code_builder/library_builder.dart @@ -21,10 +21,11 @@ const Reference stringRefer = Reference('String'); const Reference pageRouteType = Reference('PageRouteInfo', autoRouteImport); /// Builds a list type reference of type [reference] -TypeReference listRefer(Reference reference, {bool nullable = false}) => TypeReference((b) => b - ..symbol = "List" - ..isNullable = nullable - ..types.add(reference)); +TypeReference listRefer(Reference reference, {bool nullable = false}) => + TypeReference((b) => b + ..symbol = "List" + ..isNullable = nullable + ..types.add(reference)); /// Generates the router library output String generateLibrary( @@ -38,7 +39,9 @@ String generateLibrary( ); final emitter = DartEmitter( - allocator: router.usesPartBuilder ? Allocator.none : DeferredPagesAllocator(routes, router.deferredLoading), + allocator: router.usesPartBuilder + ? Allocator.none + : DeferredPagesAllocator(routes, router.deferredLoading), orderDirectives: true, useNullSafetySyntax: true, ); @@ -51,7 +54,8 @@ String generateLibrary( for (var i = 0; i < routes.length; i++) { final route = routes[i]; - if (deferredRoutes.any((e) => e.pageType == route.pageType && route.deferredLoading != true)) { + if (deferredRoutes.any( + (e) => e.pageType == route.pageType && route.deferredLoading != true)) { routes[i] = route.copyWith(deferredLoading: true); } } diff --git a/auto_route_generator/lib/src/code_builder/route_info_builder.dart b/auto_route_generator/lib/src/code_builder/route_info_builder.dart index f8ed0b25..ef1b15fa 100644 --- a/auto_route_generator/lib/src/code_builder/route_info_builder.dart +++ b/auto_route_generator/lib/src/code_builder/route_info_builder.dart @@ -7,23 +7,29 @@ import 'library_builder.dart'; import 'package:collection/collection.dart'; /// Builds a route info class and args class for the given [RouteConfig] -List buildRouteInfoAndArgs(RouteConfig r, RouterConfig router, DartEmitter emitter) { +List buildRouteInfoAndArgs( + RouteConfig r, RouterConfig router, DartEmitter emitter) { final argsClassRefer = refer('${r.getName(router.replaceInRouteName)}Args'); final parameters = r.parameters; final fragmentParam = parameters.firstWhereOrNull((e) => e.isUrlFragment); - final nonInheritedParameters = parameters.where((p) => !p.isInheritedPathParam).toList(); + final nonInheritedParameters = + parameters.where((p) => !p.isInheritedPathParam).toList(); final pageInfoRefer = refer('PageInfo', autoRouteImport); return [ Class( (b) => b - ..docs.addAll(['/// generated route for \n/// [${r.pageType?.refer.accept(emitter).toString()}]']) + ..docs.addAll([ + '/// generated route for \n/// [${r.pageType?.refer.accept(emitter).toString()}]' + ]) ..name = r.getName(router.replaceInRouteName) ..extend = TypeReference((b) { b ..symbol = 'PageRouteInfo' ..url = autoRouteImport ..types.add( - (nonInheritedParameters.isNotEmpty) ? argsClassRefer : refer('void'), + (nonInheritedParameters.isNotEmpty) + ? argsClassRefer + : refer('void'), ); }) ..fields.addAll([ @@ -33,14 +39,16 @@ List buildRouteInfoAndArgs(RouteConfig r, RouterConfig router, DartEmitte ..name = 'name' ..static = true ..type = stringRefer - ..assignment = literalString(r.getName(router.replaceInRouteName)).code, + ..assignment = + literalString(r.getName(router.replaceInRouteName)).code, ), Field( (b) => b ..name = 'page' ..static = true ..type = pageInfoRefer - ..assignment = pageInfoRefer.newInstance([refer('name')], {'builder': _buildMethod(r, router)}).code, + ..assignment = pageInfoRefer.newInstance( + [refer('name')], {'builder': _buildMethod(r, router)}).code, ), ]) ..constructors.add( @@ -49,7 +57,8 @@ List buildRouteInfoAndArgs(RouteConfig r, RouterConfig router, DartEmitte b ..constant = parameters.isEmpty ..optionalParameters.addAll([ - ...buildArgParams(nonInheritedParameters, emitter, toThis: false), + ...buildArgParams(nonInheritedParameters, emitter, + toThis: false), Parameter((b) => b ..named = true ..name = 'children' @@ -92,7 +101,8 @@ List buildRouteInfoAndArgs(RouteConfig r, RouterConfig router, DartEmitte ), ), ), - if (fragmentParam != null) 'fragment': refer(fragmentParam.name), + if (fragmentParam != null) + 'fragment': refer(fragmentParam.name), 'initialChildren': refer('children'), }).code); }, @@ -107,7 +117,9 @@ List buildRouteInfoAndArgs(RouteConfig r, RouterConfig router, DartEmitte ...nonInheritedParameters.map((param) => Field((b) => b ..modifier = FieldModifier.final$ ..name = param.name - ..type = param is FunctionParamConfig ? param.funRefer : param.type.refer)), + ..type = param is FunctionParamConfig + ? param.funRefer + : param.type.refer)), ]) ..constructors.add( Constructor((b) => b @@ -133,7 +145,9 @@ List buildRouteInfoAndArgs(RouteConfig r, RouterConfig router, DartEmitte } /// Builds a list of [Parameter]s from the given [parameters] -Iterable buildArgParams(List parameters, DartEmitter emitter, {bool toThis = true}) { +Iterable buildArgParams( + List parameters, DartEmitter emitter, + {bool toThis = true}) { return parameters.map( (p) => Parameter( (b) { @@ -152,15 +166,19 @@ Iterable buildArgParams(List parameters, DartEmitter emi ..toThis = toThis ..required = p.isRequired || p.isPositional ..defaultTo = defaultCode; - if (!toThis) b.type = p is FunctionParamConfig ? p.funRefer : p.type.refer; + if (!toThis) + b.type = p is FunctionParamConfig ? p.funRefer : p.type.refer; }, ), ); } Expression _buildMethod(RouteConfig r, RouterConfig router) { - final useConsConstructor = r.hasConstConstructor && !(r.deferredLoading ?? router.deferredLoading); - var constructedPage = useConsConstructor ? r.pageType!.refer.constInstance([]) : _getPageInstance(r); + final useConsConstructor = + r.hasConstConstructor && !(r.deferredLoading ?? router.deferredLoading); + var constructedPage = useConsConstructor + ? r.pageType!.refer.constInstance([]) + : _getPageInstance(r); if (r.hasWrappedRoute == true) { constructedPage = refer('WrappedRoute', autoRouteImport).newInstance( @@ -174,18 +192,25 @@ Expression _buildMethod(RouteConfig r, RouterConfig router) { } final inheritedParameters = r.parameters.where((p) => p.isInheritedPathParam); - final nonInheritedParameters = r.parameters.where((p) => !p.isInheritedPathParam); + final nonInheritedParameters = + r.parameters.where((p) => !p.isInheritedPathParam); return Method( (b) => b ..requiredParameters.add( Parameter((b) => b.name = 'data'), ) ..body = Block((b) => b.statements.addAll([ - if ((!r.hasUnparsableRequiredArgs) && r.parameters.any((p) => p.isPathParam) || + if ((!r.hasUnparsableRequiredArgs) && + r.parameters.any((p) => p.isPathParam) || inheritedParameters.isNotEmpty) - declareFinal('pathParams').assign(refer('data').property('inheritedPathParams')).statement, - if (!r.hasUnparsableRequiredArgs && r.parameters.any((p) => p.isQueryParam)) - declareFinal('queryParams').assign(refer('data').property('queryParams')).statement, + declareFinal('pathParams') + .assign(refer('data').property('inheritedPathParams')) + .statement, + if (!r.hasUnparsableRequiredArgs && + r.parameters.any((p) => p.isQueryParam)) + declareFinal('queryParams') + .assign(refer('data').property('queryParams')) + .statement, if (nonInheritedParameters.isNotEmpty) declareFinal('args') .assign( @@ -195,12 +220,16 @@ Expression _buildMethod(RouteConfig r, RouterConfig router) { (b) => b ..lambda = true ..body = r.pathQueryParams.isEmpty - ? refer('${r.getName(router.replaceInRouteName)}Args').constInstance([]).code - : refer('${r.getName(router.replaceInRouteName)}Args').newInstance( + ? refer('${r.getName(router.replaceInRouteName)}Args') + .constInstance([]).code + : refer('${r.getName(router.replaceInRouteName)}Args') + .newInstance( [], Map.fromEntries( nonInheritedParameters - .where((p) => (p.isPathParam || p.isQueryParam || p.isUrlFragment)) + .where((p) => (p.isPathParam || + p.isQueryParam || + p.isUrlFragment)) .map( (p) => MapEntry( p.name, @@ -239,7 +268,9 @@ Expression _getPageInstance(RouteConfig r) { Map.fromEntries(r.namedParams.map( (p) => MapEntry( p.name, - p.isInheritedPathParam ? _getUrlPartAssignment(p) : refer('args').property(p.name), + p.isInheritedPathParam + ? _getUrlPartAssignment(p) + : refer('args').property(p.name), ), )), ); diff --git a/auto_route_generator/lib/src/models/resolved_type.dart b/auto_route_generator/lib/src/models/resolved_type.dart index 239ff97a..f614203f 100644 --- a/auto_route_generator/lib/src/models/resolved_type.dart +++ b/auto_route_generator/lib/src/models/resolved_type.dart @@ -1,4 +1,5 @@ -import 'package:code_builder/code_builder.dart' show TypeReference, RecordType, Reference; +import 'package:code_builder/code_builder.dart' + show TypeReference, RecordType, Reference; /// A class that represents a resolved type. /// @@ -61,10 +62,15 @@ class ResolvedType { ..url = import ..isNullable = isNullable ..positionalFieldTypes.addAll( - typeArguments.where((e) => !e.isNamedRecordField).map((e) => e.refer), + typeArguments + .where((e) => !e.isNamedRecordField) + .map((e) => e.refer), ) ..namedFieldTypes.addAll({ - for (final entry in [...typeArguments.where((e) => e.isNamedRecordField)]) entry.nameInRecord!: entry.refer + for (final entry in [ + ...typeArguments.where((e) => e.isNamedRecordField) + ]) + entry.nameInRecord!: entry.refer }), ); } @@ -82,7 +88,10 @@ class ResolvedType { @override bool operator ==(Object other) => - identical(this, other) || other is ResolvedType && runtimeType == other.runtimeType && identity == other.identity; + identical(this, other) || + other is ResolvedType && + runtimeType == other.runtimeType && + identity == other.identity; @override int get hashCode => import.hashCode ^ name.hashCode; @@ -95,7 +104,8 @@ class ResolvedType { 'isNullable': this.isNullable, 'isRecordType': this._isRecordType, if (nameInRecord != null) 'nameInRecord': this.nameInRecord, - if (typeArguments.isNotEmpty) 'typeArguments': this.typeArguments.map((e) => e.toJson()).toList(), + if (typeArguments.isNotEmpty) + 'typeArguments': this.typeArguments.map((e) => e.toJson()).toList(), }; } diff --git a/auto_route_generator/lib/src/models/route_config.dart b/auto_route_generator/lib/src/models/route_config.dart index 2c433b3b..92f83a0e 100644 --- a/auto_route_generator/lib/src/models/route_config.dart +++ b/auto_route_generator/lib/src/models/route_config.dart @@ -17,7 +17,6 @@ class RouteConfig { /// the class name of the route final String className; - /// the parameters of the route final List parameters; @@ -58,10 +57,12 @@ class RouteConfig { } /// Returns all the required params - Iterable get requiredParams => parameters.where((p) => p.isPositional && !p.isOptional); + Iterable get requiredParams => + parameters.where((p) => p.isPositional && !p.isOptional); /// Returns all the optional params - Iterable get positionalParams => parameters.where((p) => p.isPositional); + Iterable get positionalParams => + parameters.where((p) => p.isPositional); /// Returns all the named params Iterable get namedParams => parameters.where((p) => p.isNamed); @@ -71,7 +72,8 @@ class RouteConfig { var nameToUse; if (name != null) { nameToUse = name; - } else if (replacementInRouteName != null && replacementInRouteName.split(',').length == 2) { + } else if (replacementInRouteName != null && + replacementInRouteName.split(',').length == 2) { var parts = replacementInRouteName.split(','); nameToUse = className.replaceAll(RegExp(parts[0]), parts[1]); } else { @@ -81,8 +83,8 @@ class RouteConfig { } /// Whether this route has arguments that can't be parsed - bool get hasUnparsableRequiredArgs => - parameters.any((p) => (p.isRequired || p.isPositional) && !p.isPathParam && !p.isQueryParam); + bool get hasUnparsableRequiredArgs => parameters.any((p) => + (p.isRequired || p.isPositional) && !p.isPathParam && !p.isQueryParam); /// Clones the route config with the given parameters RouteConfig copyWith({ @@ -145,7 +147,9 @@ class RouteConfig { return RouteConfig( name: map['name'] as String?, pathParams: pathParams, - pageType: map['pageType'] == null ? null : ResolvedType.fromJson(map['pageType']), + pageType: map['pageType'] == null + ? null + : ResolvedType.fromJson(map['pageType']), className: map['className'] as String, parameters: parameters, hasWrappedRoute: map['hasWrappedRoute'] as bool?, diff --git a/auto_route_generator/lib/src/models/route_parameter_config.dart b/auto_route_generator/lib/src/models/route_parameter_config.dart index 7033e827..cdd8829a 100644 --- a/auto_route_generator/lib/src/models/route_parameter_config.dart +++ b/auto_route_generator/lib/src/models/route_parameter_config.dart @@ -47,6 +47,7 @@ class ParamConfig { /// whether the parameter is a url fragment final bool isUrlFragment; + /// whether the parameter is an inherited path param final bool isInheritedPathParam; @@ -102,7 +103,7 @@ class ParamConfig { case 'bool': return type.isNullable ? 'optBool' : 'getBool'; - case 'List' : + case 'List': return type.isNullable ? 'optList' : 'getList'; default: return 'get'; @@ -151,7 +152,6 @@ class ParamConfig { isQueryParam: map['isQueryParam'] as bool, isUrlFragment: map['isUrlFragment'] as bool, defaultValueCode: map['defaultValueCode'] as String?, - ); } } diff --git a/auto_route_generator/lib/src/models/router_config.dart b/auto_route_generator/lib/src/models/router_config.dart index 701435e2..854f3074 100644 --- a/auto_route_generator/lib/src/models/router_config.dart +++ b/auto_route_generator/lib/src/models/router_config.dart @@ -1,5 +1,3 @@ - - /// RouterConfig class RouterConfig { /// The name of the router class @@ -23,7 +21,6 @@ class RouterConfig { /// The list of directories to generate for final List generateForDir; - /// Default constructor const RouterConfig({ required this.routerClassName, diff --git a/auto_route_generator/lib/src/resolvers/route_config_resolver.dart b/auto_route_generator/lib/src/resolvers/route_config_resolver.dart index 8eaa892a..c4cedc11 100644 --- a/auto_route_generator/lib/src/resolvers/route_config_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/route_config_resolver.dart @@ -25,8 +25,8 @@ class RouteConfigResolver { final classElement = element as ClassElement; final page = classElement.thisType; - final hasWrappedRoute = - classElement.allSupertypes.any((e) => e.getDisplayString(withNullability: false) == 'AutoRouteWrapper'); + final hasWrappedRoute = classElement.allSupertypes.any((e) => + e.getDisplayString(withNullability: false) == 'AutoRouteWrapper'); var pageType = _typeResolver.resolveType(page); var className = page.getDisplayString(withNullability: false); @@ -61,8 +61,10 @@ class RouteConfigResolver { var pathParameters = parameters.where((element) => element.isPathParam); if (parameters.any((p) => p.isPathParam || p.isQueryParam)) { - var unParsableRequiredArgs = - parameters.where((p) => (p.isRequired || p.isPositional) && !p.isPathParam && !p.isQueryParam); + var unParsableRequiredArgs = parameters.where((p) => + (p.isRequired || p.isPositional) && + !p.isPathParam && + !p.isQueryParam); if (unParsableRequiredArgs.isNotEmpty) { print( '\nWARNING => Because [$className] has required parameters ${unParsableRequiredArgs.map((e) => e.paramName)} ' diff --git a/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart b/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart index 4fc2f639..a054b7db 100644 --- a/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/route_parameter_resolver.dart @@ -31,7 +31,8 @@ class RouteParameterResolver { var nameOrAlias = paramName; var isInheritedPathParam = false; - final isUrlFragment = _urlFragmentChecker.hasAnnotationOfExact(parameterElement); + final isUrlFragment = + _urlFragmentChecker.hasAnnotationOfExact(parameterElement); if (pathParamAnnotation != null) { isInheritedPathParam = @@ -56,12 +57,15 @@ class RouteParameterResolver { } throwIf( - [isUrlFragment, pathParamAnnotation != null, queryParamAnnotation != null].where((e) => e).length > 1, + [isUrlFragment, pathParamAnnotation != null, queryParamAnnotation != null] + .where((e) => e) + .length > + 1, '${parameterElement.name} can only be annotated with one of @PathParam, @QueryParam or @urlFragment', element: parameterElement, ); - if(isUrlFragment){ + if (isUrlFragment) { throwIf( type.name != 'String', 'UrlFragments must be of type String', @@ -88,7 +92,6 @@ class RouteParameterResolver { isQueryParam: queryParamAnnotation != null, isUrlFragment: isUrlFragment, defaultValueCode: parameterElement.defaultValueCode, - ); } diff --git a/auto_route_generator/lib/src/resolvers/router_config_resolver.dart b/auto_route_generator/lib/src/resolvers/router_config_resolver.dart index 02c07fee..dfdc6e1d 100644 --- a/auto_route_generator/lib/src/resolvers/router_config_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/router_config_resolver.dart @@ -6,7 +6,6 @@ import '../models/router_config.dart'; /// Extracts and holds router configs class RouterConfigResolver { - /// Default constructor RouterConfigResolver(); @@ -18,7 +17,6 @@ class RouterConfigResolver { bool usesPartBuilder = false, int? cacheHash, }) { - final deferredLoading = autoRouter.peek('deferredLoading')?.boolValue ?? false; var replaceInRouteName = autoRouter.peek('replaceInRouteName')?.stringValue; diff --git a/auto_route_generator/lib/src/resolvers/type_resolver.dart b/auto_route_generator/lib/src/resolvers/type_resolver.dart index bd182d32..f9b8faf8 100644 --- a/auto_route_generator/lib/src/resolvers/type_resolver.dart +++ b/auto_route_generator/lib/src/resolvers/type_resolver.dart @@ -1,12 +1,13 @@ import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/nullability_suffix.dart' show NullabilitySuffix; +import 'package:analyzer/dart/element/nullability_suffix.dart' + show NullabilitySuffix; import 'package:analyzer/dart/element/type.dart' show DartType, ParameterizedType, RecordType; import 'package:auto_route_generator/src/models/resolved_type.dart'; import 'package:path/path.dart' as p; - const _unPreferredImports = {'dart:ui'}; + /// A Helper class that resolves types class TypeResolver { /// The list of resolved libraries in [BuildStep] @@ -25,18 +26,21 @@ class TypeResolver { return null; } - final fallBackImports = {}; + final fallBackImports = {}; for (var lib in libs) { - if (!_isCoreDartType(lib) && lib.exportNamespace.definedNames.values.contains(element)) { + if (!_isCoreDartType(lib) && + lib.exportNamespace.definedNames.values.contains(element)) { final uri = lib.source.uri; - if(_unPreferredImports.contains(uri.toString())){ + if (_unPreferredImports.contains(uri.toString())) { fallBackImports.add(uri.toString()); continue; - } + } if (uri.scheme == 'asset') { return _assetToPackage(lib.source.uri); } - return targetFile == null ? lib.identifier : _relative(uri, targetFile!); + return targetFile == null + ? lib.identifier + : _relative(uri, targetFile!); } } return fallBackImports.firstOrNull; @@ -61,12 +65,16 @@ class TypeResolver { String _relative(Uri fileUri, Uri to) { var libName = to.pathSegments.first; - if ((to.scheme == 'package' && fileUri.scheme == 'package' && fileUri.pathSegments.first == libName) || + if ((to.scheme == 'package' && + fileUri.scheme == 'package' && + fileUri.pathSegments.first == libName) || (to.scheme == 'asset' && fileUri.scheme != 'package')) { if (fileUri.path == to.path) { return fileUri.pathSegments.last; } else { - return p.posix.relative(fileUri.path, from: to.path).replaceFirst('../', ''); + return p.posix + .relative(fileUri.path, from: to.path) + .replaceFirst('../', ''); } } else { return fileUri.toString(); @@ -84,7 +92,8 @@ class TypeResolver { types.add(ResolvedType( name: recordField.type.element?.name ?? 'void', import: resolveImport(recordField.type.element), - isNullable: recordField.type.nullabilitySuffix == NullabilitySuffix.question, + isNullable: + recordField.type.nullabilitySuffix == NullabilitySuffix.question, typeArguments: _resolveTypeArguments(recordField.type), )); } @@ -92,7 +101,8 @@ class TypeResolver { types.add(ResolvedType( name: recordField.type.element?.name ?? 'void', import: resolveImport(recordField.type.element), - isNullable: recordField.type.nullabilitySuffix == NullabilitySuffix.question, + isNullable: + recordField.type.nullabilitySuffix == NullabilitySuffix.question, typeArguments: _resolveTypeArguments(recordField.type), nameInRecord: recordField.name, )); @@ -127,9 +137,9 @@ class TypeResolver { final import = resolveImport(effectiveElement); final typeArgs = []; final alias = type.alias; - if(alias != null) { - typeArgs.addAll(alias.typeArguments.map(resolveType)); - }else { + if (alias != null) { + typeArgs.addAll(alias.typeArguments.map(resolveType)); + } else { typeArgs.addAll(_resolveTypeArguments(type)); } if (type is RecordType && type.alias == null) { @@ -142,7 +152,8 @@ class TypeResolver { } return ResolvedType( - name: effectiveElement?.displayName ?? type.getDisplayString(withNullability: false), + name: effectiveElement?.displayName ?? + type.getDisplayString(withNullability: false), isNullable: type.nullabilitySuffix == NullabilitySuffix.question, import: import, typeArguments: typeArgs,