Flutter route generator

Overview

MIT License stars pub version Discord Badge

Buy Me A Coffee

--- for more docs with examples https://autoroute.vercel.app

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

dependencies:        
 auto_route: [latest-version]        
       
dev_dependencies:        
 auto_route_generator: [latest-version]        
 build_runner:        

Setup And Usage

Create a placeholder class and annotate it with @MaterialAutoRouter which takes a list of routes as a required argument.

Note: Unless you want to generate a part of file (.gr.dart) The name of the router must be prefixed with $ so we have a generated class with the same name minus the $.

        
// @CupertinoAutoRouter        
// @AdaptiveAutoRouter        
// @CustomAutoRouter        
@MaterialAutoRouter(        
  replaceInRouteName: 'Page,Route',        
  routes: <AutoRoute>[        
    AutoRoute(page: BookListPage, initial: true),        
    AutoRoute(page: BookDetailsPage),        
  ],        
)        
class $AppRouter {}        

Using part builder ( New in version 3.0.0+)

To generate a part-of file instead of a stand alone AppRouter class, simply add a Part Directive to your AppRouter and extend the generated private router.

part 'app_router.gr.dart'  
  
@MaterialAutoRouter(        
  replaceInRouteName: 'Page,Route',        
  routes: <AutoRoute>[        
    AutoRoute(page: BookListPage, initial: true),        
    AutoRoute(page: BookDetailsPage),        
  ],        
)        
// extend the generated private router  
class AppRouter extends _$AppRouter{}        

Tip: You can Shorten auto-generated route names from e.g. BookListPageRoute to BookListRoute using the replaceInRouteName argument.

Now simply run the generator

Use the [watch] flag to watch the files' system for edits and rebuild as necessary.

flutter packages pub run build_runner watch        

if you want the generator to run one time and exits use

flutter packages pub run build_runner build        

Finalize the setup

after you run the generator your router class will be generated, hook it up with MaterialApp.

// assuing 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(
      routerDelegate: _appRouter.delegate(),
      routeInformationParser: _appRouter.defaultRouteParser(),
    );
  }
}

Generated Routes

A PageRouteInfo object will be generated for every declared AutoRoute, These objects hold path information plus strongly-typed page arguments which are extracted from the page's default constructor. Think of them as string path segments on steroid.

class BookListRoute extends PageRouteInfo {        
  const BookListRoute() : super(name, path: '/books');        
        
  static const String name = 'BookListRoute';        
}        

if the declared route has children AutoRoute will add a children parameter to its constructor to be used in nested navigation. more on that here.

class UserRoute extends PageRouteInfo {        
   UserRoute({List<PagerouteInfo> children}) :        
    super(        
         name,         
         path: '/user/:id',        
         initialChildren: children);        
  static const String name = 'UserRoute';        
}        

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.

// 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 using paths      
router.pushNamed('/books')       
    
// removes last entry in stack and pushs provided route     
// if last entry == provided route page will just be updated    
router.replace(const BooksListRoute())        
// or by using 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 using paths      
router.navigateNamed('/books')    
  
// on Web it calls window.history.back();
// on Native it navigates you back 
// to the previous location
router.navigateBack();

// adds a list of routes to the pages stack at once    
router.pushAll([    
   BooksListRoute(),    
   BookDetailsRoute(id:1),    
]);    
    
// This's like providing a completely new stack as it rebuilds the stack    
// with the list of passed routes    
// entires might just update if alright exist    
router.replaceAll([    
   LoginRoute()    
]);    
// pops the last page unless stack has 1 entry        
context.router.pop();       
// keeps poping routes until predicate is satisfied    
context.router.popUntil((route) => route.name == 'HomeRoute');    
// a simplifed version of the above line    
context.router.popUntilRouteWithName('HomeRoute');    
// 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 satisfis the predicate    
// this works exactly like removing items from a regualar List    
// <PageRouteInfo>[...].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.navigateBack();   
context.popRoute();    

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.

class BookDetailsPage extends StatelessWidget {        
 const BookDetailsRoute({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 it's corresponding page.

router.push(BookDetailsRoute(book: book));        

Note: all args 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

var result = await router.push(LoginRoute());        

then inside of your LoginPage pop with results

router.pop(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.

AutoRoute<bool>(page: LoginPage),     

we push and specify the type of results we're expecting

var result = await router.push<bool>(LoginRoute());        

and of course we pop with the same type

router.pop<bool>(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:

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 it's corresponding page.

context.router.push(        
      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

onRateBook(RESULT);        
context.router.pop();        

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.

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.

@MaterialAutoRouter(        
  replaceInRouteName: 'Page,Route',        
  routes: <AutoRoute>[        
    AutoRoute(        
      path: '/dashboard',        
      page: DashboardPage,        
      children: [        
        AutoRoute(path: 'users', page: UsersPage),        
        AutoRoute(path: 'posts', page: PostsPage),    
        AutoRoute(path: 'settings', page: SettingsPage),          
      ],        
    ),    
    AutoRoute(path: '/login', page: LoginPage)    
  ],        
)        
class $AppRouter {}        

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.

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(),    
        )    
      ],    
    );    
  }    
}    

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 '' or set it as initial.

   AutoRoute(        
      path: '/dashboard',        
      page: UserPage,        
      children: [        
        AutoRoute(path: '', page: UsersPage),    
        //The same thing can be done using the initial flag    
        //AutoRoute(page: UsersPage,initial: true),        
        AutoRoute(path: 'posts', page: PostsPage),        
      ],        
    ),        

or by using a RedirectRoute

	AutoRoute(        
	path: '/dashboard',        
	page: UserPage,        
		children: [        
			RedirectRoute(path: '', redirectTo: 'users'),        
			AutoRoute(path: 'users', page: UsersPage),        
			AutoRoute(path: 'posts', page: PostsPage),         
		],        
	),  

which can be simplified to the following where auto_route generates the redirect code for you.

   AutoRoute(        
      path: '/dashboard',        
      page: UserPage,        
      children: [        
        // RedirectRoute(path: '', redirectTo: 'users'),        
        AutoRoute(path: 'users', page: UsersPage, initial: true),        
        AutoRoute(path: 'posts', page: PostsPage),         
      ],        
    ),        

Things to keep in mind when implementing nested navigation

1- Each router manages it's 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 issues, 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 finally it 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 tree nested children, users, posts and settings.

class DashboardPage extends StatelessWidget {    
  @override    
  Widget build(BuildContext context) {    
    return AutoTabsRouter(    
    // list of your tab routes    
    // routes used here must be declaraed as children    
    // routes of /dashboard     
      routes: const [    
        UsersRoute(),    
        PostsRoute(),    
        SettingsRoute(),    
      ],    
      builder: (context, child, animation) {    
        // 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    
        //     
        //alterntivly you could use a global key    
        return Scaffold(    
            body: FadeTransition(    
              opacity: animation,    
              // the passed child is techinaclly our animated selected-tab page    
              child: 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.

class DashboardPage extends StatelessWidget {    
    
 @override      
Widget build(context) {      
 @override    
  Widget build(context) {    
    return AutoTabsScaffold(    
       routes: const [    
        UsersRoute(),    
        PostsRoute(),    
        SettingsRoute(),    
      ],    
      bottomNavigationBuilder: (_,tabsRouter) {    
          return BottomNavigationBar(    
              currentIndex: tabsRouter.activeIndex,    
              onTap: tabsRouter.setActiveIndex    
              items: [    
                BottomNavigationBarItem(label: 'Users',...),    
                BottomNavigationBarItem(label: 'Posts',...),    
                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 context.

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.

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

As you can tell from the above diagram it's possible to access parent routing controllers by calling router.parent<T>(), we're using a generic function because we have too 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.

router.parent<StackRouter>() // this returns  the parent router as a Stack Routing controller        
router.parent<TabsRouter>() // this returns athe 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.

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

class DashboardPage extends StatefulWidget {    
  @override    
  _DashboardPageState createState() => _DashboardPageState();    
}    
    
class _DashboardPageState extends State<DashboardPage> {    
  final _innerRouterKey = GlobalKey<AutoRouterState>();    
  @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.

// assuming this's the root router        
context.innerRouterOf<StackRouter>(UserRoute.name)         
// or if we're usign an AutoTabsRouter inside of DashboardPage    
context.innerRouterOf<TabsRouter>(UserRoute.name)      

Accessing the DashboardPage inner router from the previous example.

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<StackRouter>(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

// declerate your route as a global vairable    
final appRouter = AppRouter();      
    
class MyApp extends StatefulWidget {    
    
  @override    
  Widget build(BuildContext context) {    
    return MaterialApp.router(    
      routerDelegate: AutoRouterDelegate(appRouter),    
      routeInformationParser: appRouter.defaultRouteParser(),    
      );    
    }    

Note: using global variable is not recommended and is considered a 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.

void main(){    
// make sure you register it as a Singleton or a lazySingleton    
  getIt.registerSingleton<AppRouter>(AppRouter());    
  runApp(MyApp());    
 }    
    
class MyApp extends StatefulWidget {    
  @override    
  Widget build(BuildContext context) {    
    final router = getIt<AppRouter>();    
    return MaterialApp.router(    
      routerDelegate: AutoRouterDelegate(router),    
      routeInformationParser: router.defaultRouteParser(),    
      );    
    }    

now you can access to your router anywhere inside of your App without using context.

getIt<AppRouter>().push(...);    

Note: navigating without context is not recommended in nested navigation.

Working with Paths

Working with paths in AutoRoute is optional because PageRouteInfo objects are matched by name unless pushed as a string using the initialDeepLink 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.

 AutoRoute(path: '/books', page: BookListPage),        

Path Parameters (dynamic segments)

You can define a dynamic segment by prefixing it with a colon

 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.

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.

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.

 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.

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.

<AutoRoute> [        
     RedirectRoute(path: '/', redirectTo: '/books'),        
     AutoRoute(path: '/books', page: BookListPage),        
 ]        

When redirecting initial routes the above setup can be simplified by setting the /books path as initial and auto_route will automatically generate the required redirect code for you.

<AutoRoute> [          
     AutoRoute(path: '/books', page: BookListPage, initial: true),        
 ]        

Note: RedirectRoutes are fully matched.

Wildcards

auto_route supports wildcard matching to handle invalid or undefined paths.

AutoRoute(path: '*', page: UnknownRoutePage)        
// it could be used with defined prefixes        
AutoRoute(path: '/profile/*', page: ProfilePage)        
// 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 auto_route package
and implementing our logic inside of the onNavigation method.

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(authenitcated){    
       // if user is authenticated we continue    
        resolver.next(true);    
      }else{    
         // we redirect the user to our login page    
         router.push(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.

 AutoRoute(page: ProfileScreen, guards: [AuthGuard]);    

After we run code generation, our router will have a required named argument called authGuard or whatever your guard name is

// we pass our AuthGuard to the generated router.    
final _appRouter = AppRouter(authGuard: AuthGuard());    

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.

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.

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 root delegate AutoRouterDelegate.
Important notice that navigatorObservers property is a builder function that returns a list of observes and the reason for that is a navigator observer instance can only be used by a single router, so unless you're using a one single router or you don't want your nested routers to inherit observers make sure navigatorObservers builder always returns fresh observer instances.

   return MaterialApp.router(    
      routerDelegate: AutoRouterDelegate(    
        _appRouter,    
        navigatorObservers: () => [MyObserver()],    
      ),    
      routeInformationParser: _appRouter.defaultRouteParser(),    
    );    

the following approach won't work if you have nested routers unless they don't inherit the observers.

   final _observer = MyObserver();    
   return MaterialApp.router(    
      routerDelegate: AutoRouterDelegate(    
        _appRouter,    
        // this should always return new instances    
        navigatorObservers: () => [_observer],    
      ),    
      routeInformationParser: _appRouter.defaultRouteParser(),    
    );    

Every nested router can have it's own observers and inherit it's parent's.

 AutoRouter(    
    inheritNavigatorObservers: true, // true by default    
    navgiatorObservers:()=> [list of observers]);    
        
 AutoTabsRouter(    
    inheritNavigatorObservers: true, // true by default    
    navgiatorObservers:()=> [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

   return MaterialApp.router(    
      routerDelegate: AutoRouterDelegate(    
        _appRouter,    
       // Provide an AutoRouteObserver instance    
        navigatorObservers: () => [AutoRouteObserver()],    
      ),    
      routeInformationParser: _appRouter.defaultRouteParser(),    
    );    

Next we use an AutoRouteAware mixin which is a RouteAware mixin with tab support to provided the needed listeners then subscribe to our AutoRouteObserver.

class BooksListPage extends State<BookListPage> with AutoRouteAware {    
   AutoRouteObserver? _observer;    
       
  @override    
  void didChangeDependencies() {    
    super.didChangeDependencies();    
    // RouterScope exposes the list of provided observers    
    // including inherited observers    
   _observer = RouterScope.of(context).firstObserverOfType<AutoRouteObserver>();    
    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() {}    
}    

Customizations

MaterialAutoRouter | CupertinoAutoRouter | AdaptiveAutoRouter
Property Default value Definition
preferRelativeImports [bool] true if true relative imports will be used when possible
replaceInRouteName [String] '' used to replace conventional words in generated route name (whatToReplacePattern,replacement)

CustomAutoRouter

Property Default value Definition
customRouteBuilder null used to provide a custom route, it takes in BuildContext and a CustomPage and returns a PageRoute
transitionsBuilder null extension for the transitionsBuilder property in PageRouteBuilder
opaque true extension for the opaque property in PageRouteBuilder
barrierDismissible false extension for the barrierDismissible property in PageRouteBuilder
durationInMilliseconds null extension for the transitionDuration(millieSeconds) property in PageRouteBuilder
reverseDurationInMilliseconds null extension for the reverseDurationInMilliseconds(millieSeconds) property in PageRouteBuilder

MaterialRoute | CupertinoRoute | AdaptiveRoute | CustomRoute

Property Default value Definition
initial false sets path to '/' or '' unless path is provided then it generates auto redirect to it.
path null an auto generated path will be used if not provided
name null this will be the name of the generated route, if not provided a generated name will be used
usePathAsKey false if true path is used as page key instead of name
fullscreenDialog false extension for the fullscreenDialog property in PageRoute
maintainState true extension for the maintainState property in PageRoute
meta {} primitive meta data to be passed to the consumed route

CupertinoRoute Specific => CupertinoPageRoute

Property Default value Definition
title null extension for the title property in CupertinoPageRoute

CustomRoute Specific => PageRouteBuilder

Property Default value Definition
transitionsBuilder null extension for the transitionsBuilder property in PageRouteBuilder
customRouteBuilder null used to provide a custom route, it takes in BuildContext and a CustomPage and returns a PageRoute
opaque true extension for the opaque property in PageRouteBuilder
barrierDismissible false extension for the barrierDismissible property in PageRouteBuilder
durationInMilliseconds null extension for the transitionDuration(millieSeconds) property in PageRouteBuilder
reverseDurationInMilliseconds null extension for the reverseDurationInMilliseconds(millieSeconds) property in PageRouteBuilder

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.

CustomRoute(    
page: LoginScreen,    
//TransitionsBuilders class contains a preset of common transitions builders.     
transitionsBuilder: TransitionBuilders.slideBottom,    
durationInMilliseconds: 400)    

Tip Use @CustomAutoRouter() 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 a BuildContext, Animation<Double>, Animation<Double> 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.

Widget zoomInTransition(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {    
 // you get an animation object and a widget    
 // make your own transition    
    return ScaleTransition(scale: animation, child: child);    
  }    

Now pass the reference of your function to CustomRoute .

CustomRoute(page: ZoomInScreen, transitionsBuilder: zoomInTransition)    

Custom Route Builder

You can use your own custom route by passing a CustomRouteBuilder function to CustomRoute, there isn't a simple way to strongly-type a static function in code generation, so make sure your custom builder signature matches the following.

typedef CustomRouteBuilder = Route<T> Function<T>(      
  BuildContext context, Widget child, CustomPage page);    

Now we implement our 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.

Route<T> myCustomRouteBuilder<T>(BuildContext context, Widget child, CustomPage<T> page){      
  return PageRouteBuilder(      
  fullscreenDialog: page.fullscreenDialog,      
  // this is important      
  settings: page,      
  pageBuilder: (,__,___) => child);      
}    

We finish by passing a reference of our custom function to our CustomRoute.

CustomRoute(page: CustomPage, customRouteBuilder: myCustomRouteBuilder)    

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.

Comments
  • auto_route 2.0!

    auto_route 2.0!

    I've been re-writing auto_route to support the new 2.0 Navigator, which should explain why I haven't been active lately, anyways, I believe I'm pretty close to wrapping things up. I just want to know if there are features that weren't possible before and you guys want it in the new auto_route? also should I jump to release v2.0.0 when current auto route is not even 1.+?

    enhancement 
    opened by Milad-Akarie 46
  • Authguard not working correctly

    Authguard not working correctly

    When I use the package with Firebase auth. For Web each time the site is refreshed it will not hold the auth state. This works if I use my own router. Not sure if something is wrong in the package or I am using it wrong but I can confirm that the auth is there and working for firebase.

    `class AuthGuard extends AutoRouteGuard {
      @override
      Future<bool> canNavigate(List<PageRouteInfo> pendingRoutes, StackRouter router) async {
        if (FirebaseAuth.instance.currentUser == null) {
          router.root.push(
            TestingRoute(onResult: (success) {
              if (success) {
                print(success);
                router.root.pop();
                router.pushAll(pendingRoutes);
              }
            })
          );
          return false;
        }
        return true;
      }
    
    }`
    
    opened by rlee1990 38
  • Adds routePrefix feature and allRoutes getter generator for router and routes classes

    Adds routePrefix feature and allRoutes getter generator for router and routes classes

    What it does :

    • Adds route prefix option that can be specified for Router class so that each route in the generated Route class is prefixed by this route.
    • Adds a way to access all the generated routes in the Router class by generating a getter method for the Router.
    • Fixes some issues regarding Function parameters in the Route Class.

    Fixes Issues :

    #88 #91 #90

    Results based on this code :

    This is my $Router class :

    $Router class

    @MaterialAutoRouter(routesClassName: 'BusRoute', generateRouteList: true , routePrefix: '/bus/')
    class $MyBusRouter{
      BusFilterScreen busFilterScreen ;
      BaseLoadingScreen baseLoadingScreen ; 
    }
    

    Generated Class :

    abstract class BusRoute {
      static const busFilterScreen = '/bus/bus-filter-screen';
      static const baseLoadingScreen = '/bus/base-loading-screen';
      static const all = [
        busFilterScreen,
        baseLoadingScreen,
      ];
    }
    
    class MyBusRouter extends RouterBase {
      @override
      List<String> get allRoutes => const [
            BusRoute.busFilterScreen,
            BusRoute.baseLoadingScreen,
          ];
    
      //This will probably be removed in future versions
      //you should call ExtendedNavigator.ofRouter<Router>() directly
      static ExtendedNavigatorState get navigator =>
          ExtendedNavigator.ofRouter<MyBusRouter>();
    
      @override
      Route<dynamic> onGenerateRoute(RouteSettings settings) {
        final args = settings.arguments;
        switch (settings.name) {
          case BusRoute.busFilterScreen:
            if (hasInvalidArgs<BusFilterScreenArguments>(args, isRequired: true)) {
              return misTypedArgsRoute<BusFilterScreenArguments>(args);
            }
            final typedArgs = args as BusFilterScreenArguments;
            return MaterialPageRoute<dynamic>(
              builder: (context) => BusFilterScreen(
                  key: typedArgs.key,
                  tripId: typedArgs.tripId,
                  filterScreenManager: typedArgs.filterScreenManager),
              settings: settings,
            );
          case BusRoute.baseLoadingScreen:
            if (hasInvalidArgs<BaseLoadingScreenArguments>(args)) {
              return misTypedArgsRoute<BaseLoadingScreenArguments>(args);
            }
            final typedArgs =
                args as BaseLoadingScreenArguments ?? BaseLoadingScreenArguments();
            return MaterialPageRoute<dynamic>(
              builder: (context) => BaseLoadingScreen(
                  key: typedArgs.key,
                  showAppBar: typedArgs.showAppBar,
                  appBarTitle: typedArgs.appBarTitle,
                  showThreeDotMenu: typedArgs.showThreeDotMenu),
              settings: settings,
            );
          default:
            return unknownRoutePage(settings.name);
        }
      }
    }
    

    Regarding issue #90

    I will raise a separate PR to convert the List getter into a Set getter for optimisation purpose.

    Thank you for this awesome library 😄 will try to add a PR for fixing issue #91 , but I have no idea how I might fix it . May be you can help me here :)

    opened by nateshmbhat 37
  • invalid member on null: 'key'

    invalid member on null: 'key'

    I am receiving an error invalid member on null: 'key' when trying to build the app.

    `class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      
      @override
      Widget build(BuildContext context) {
        final themeData = Provider.of<ThemeState>(context);
        final connectionStatus = Provider.of<ConnectionStatus>(context);
        return OverlaySupport(
          child: MultiProvider(
            providers: [
              StreamProvider<UserPublic>(
                create: (context) => FirestoreService().streamPublicUser(Provider.of<User>(context, listen: false).uid),
              ),
            ],
              child: MaterialApp(
                builder: ExtendedNavigator.builder(
                  router: SnabRouter(),
                  guards: [AuthGuard()],
                ),
              title: 'SNAB',
              theme: themeData.getTheme(),
              debugShowCheckedModeBanner: false,
            ),
          ),
        );
      }
    }`
    

    [√] Flutter (Channel master, 1.23.0-14.0.pre.84, on Microsoft Windows [Version 10.0.19041.508], locale en-US)

    [√] Android toolchain - develop for Android devices (Android SDK version 30.0.1) [√] Chrome - develop for the web [√] Android Studio (version 4.0) [√] VS Code (version 1.50.0) [√] Connected device (3 available)

    • No issues found!

    opened by rlee1990 32
  • Issue

    Issue "Error: Required named parameter 'type' must be provided." when deploying Flutter in Netlify

    Hey @Milad-Akarie, this is a great package for managing route

    Previously I managed to deploying flutter on netlify until yesterday it failed with error message:

    "Error: Required named parameter 'type' must be provided. ?.routerReportsNewRouteInformation( "

    this is deploy log on netlify image

    Strange this error is not appear when i run flutter in my devices / local browser

    this is my dependencies for auto route package

    dependencies:
       auto_route: ^2.3.0
       ...
    
    dependency_overrides:
      meta: ^1.7.0
    
    dev_dependencies:
       auto_route_generator: ^2.3.0
       build_runner: ^2.0.5
       ...
    

    and this is my AppRouter.dart

    @MaterialAutoRouter(
      replaceInRouteName: 'Page,Route',
      routes: <AutoRoute>[
    
    
        ///After modify/add new route, run "flutter packages pub run build_runner watch" in terminal to generate new route
        ///or Run "flutter packages pub run build_runner watch --delete-conflicting-outputs" when conflicting output detected
    
        ///Login
        AutoRoute(page: LoginPage, path: "/login"),
    
        ///MainNavigationPage
        AutoRoute(page: MainNavigationPage, guards: [AuthGuard], path: "/",
            children: [
              ///Dashboard
              AutoRoute(page: DashboardPage, path: "dashboard", initial: true),
    
              ///ITSP
              AutoRoute(page: ItspCompanyPage, path: "itsp"),
              AutoRoute(page: ItspRkuPage, path: "itsp/:companyName/rku/"),
              AutoRoute(page: ItspRktPage, path: "itsp/:companyName/rku/:rkuYear/rkt/"),
              AutoRoute(page: ItspRktDetailPage, path: "itsp/:companyName/rku/:rkuYear/rkt/:rktYear/"),
              AutoRoute(page: ItspTallyAddPage, path: "itsp/:companyName/rku/:rkuYear/rkt/:rktYear/add"),
              AutoRoute(page: ItspTallyUpdatePage, path: "itsp/:companyName/rku/:rkuYear/rkt/:rktYear/update/:tallyId"),
    
              ///Logging
              AutoRoute(page: LoggingOverviewPage, path: "logging"),
              AutoRoute(page: LoggingListPage, path: "logging/list"),
              AutoRoute(page: LoggingAddPAge, path: "logging/list/add"),
              AutoRoute(page: LoggingOverviewDetailPage, path: "logging/:companyId"),
    
              ///Template Form & List
              AutoRoute(page: FormPage, path: "form"),
              AutoRoute(page: ListPage, path: "list"),
    
              ///Redirect to Initial Route (Dashboard) if route name is not detected
              RedirectRoute(path: '*', redirectTo: '')
            ]
        ),
      ],
    )
    class $AppRouter {}
    

    is this error related with auto route package? do you have any suggestion about this error? thanks @Milad-Akarie

    no-issue-activity 
    opened by RizaldiWiratama 30
  • auto_route 1.0.0-beta

    auto_route 1.0.0-beta

    I just published auto_route 1.0.0-beta with very little documentation, There's still alot of work to be done Docs, Testing and improvements. I don't seem to get alot of free time lately so I'm asking you to bare with me. as I said I didn't get the chance to write the docs but If you've used auto_route before, finding your way around shouldn't be hard. I promise to be more responsive so if you have any questions about the new auto_route you can ask me here. Thank you all for your patience. https://pub.dev/packages/auto_route/versions/1.0.0-beta

    Highlights

    • deepLinking has never been easier (including same level deep linking)
    • full controller over route stack
    • route redirect
    • custom route builders (not the same as TransitionsBuilders)
    • tidy generated code using code_builder _ much more...
    opened by Milad-Akarie 30
  • Flutter 1.22 broke the library auto generation

    Flutter 1.22 broke the library auto generation

    Since the 1.22 update the auto generation keeps stuck in the

    [WARNING] No actions completed for 15.1s, waiting on:
      - auto_route_generator:autoRouteGenerator on lib/pages/cumprimento/Widgets/anexos_modal.dart
      - auto_route_generator:autoRouteGenerator on lib/pages/cumprimento/Widgets/video_preview_midias.dart
      - auto_route_generator:autoRouteGenerator on lib/pages/cumprimento/Widgets/anexo_widget.dart
      - auto_route_generator:autoRouteGenerator on lib/pages/cumprimento/cumprimento_preview_dialog.dart
      - auto_route_generator:autoRouteGenerator on lib/pages/cumprimento/cumprimento_page.dart
      .. and 11 more
    

    And in the beginning of the auto generation there is a severe error.

    [SEVERE] auto_route_generator:autoRouteGenerator on lib/main.dart:
    
    Bad state: Unexpected diagnostics:
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:152:17 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:119:41 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:133:32 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:186:51 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:88:62 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:153:38 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:64:4 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:154:25 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:18:17 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:118:48 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:132:37 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:19:11 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:159:38 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:168:32 - This requires the 'non-nullable' language feature to be enabled.
    /home/johnpinto/.local/share/flutter/bin/cache/pkg/sky_engine/lib/ui/channel_buffers.dart:47:14 - This requires the 'non-nullable' language feature to be enabled.
    

    I really like this library and I would like it to keep it in my work project, but in the state that it is now, I have no choice but to switch to the default navigator for now.

    Edit: added the output from the debug console

    Launching lib/main.dart on AOSP on IA Emulator in debug mode...
    lib/main.dart:66:21: Error: 'Router' is imported from both 'package:flutter/src/widgets/router.dart' and 'package:mobile/src/router/router.gr.dart'.
                router: Router(),
                        ^^^^^^
    lib/main.dart:65:38: Error: Inferred type argument 'dynamic' doesn't conform to the bound 'RouterBase' of the type variable 'T' on 'ExtendedNavigator<dynamic>.builder'.
     - 'RouterBase' is from 'package:auto_route/src/router_base.dart' ('../../../.local/share/flutter/.pub-cache/hosted/pub.dartlang.org/auto_route-0.6.7/lib/src/router_base.dart').
     - 'ExtendedNavigator' is from 'package:auto_route/src/extended_navigator.dart' ('../../../.local/share/flutter/.pub-cache/hosted/pub.dartlang.org/auto_route-0.6.7/lib/src/extended_navigator.dart').
    Try specifying type arguments explicitly so that they conform to the bounds.
              builder: ExtendedNavigator.builder(
                                         ^
    ../../../.local/share/flutter/.pub-cache/hosted/pub.dartlang.org/auto_route-0.6.7/lib/src/extended_navigator.dart:24:36: Context: This is the type variable whose bound isn't conformed to.
      static TransitionBuilder builder<T extends RouterBase>({
                                       ^
    
    
    FAILURE: Build failed with an exception.
    
    * Where:
    Script '/home/johnpinto/.local/share/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 904
    
    * What went wrong:
    Execution failed for task ':app:compileFlutterBuildDebug'.
    > Process 'command '/home/johnpinto/.local/share/flutter/bin/flutter'' finished with non-zero exit value 1
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 53s
    Exception: Gradle task assembleDebug failed with exit code 1
    Exited (sigterm)
    
    

    Edit2: I was capable to make it work, the problem is that the new navigator 2.0 has a class with the same Router name on it, but the code generation is still borked.

    opened by JohnPinto 30
  • router.push will push the route behind the current widget route

    router.push will push the route behind the current widget route

    Hey again, The last updates introduced a new bug with pushWidget. The actual pushing of widget is working fine, the bug itself happen when pushing a route when the current page is a widget and not a route.

    So the flow is like this: Initial route -> Push widget -> Push route -> the pushed route is not showing -> popping the widget route -> the pushed route is showing.

    It's like auto route doesn't acknowledge the pushed widget is in the stack.

    Also worth noting that the route I'm trying to push is defined in the root, so there shouldn't be a problem of nesting.

    Please help, Thanks

    opened by naamapps 29
  • Navigation Observer not being called in tabs router

    Navigation Observer not being called in tabs router

    Hi,

    I've been trying to observe routes using a NavigationObserver. It works fine for root level pages, but when setting usesTabsRouter: true it seems child elements are not observed. Is there a way to this, or a way to set another observer for the child routes? I've had a good look through the documentation but couldn't see anything obvious to make this happen.

    Here are some screenshots showing the code. It's a basic set up, with some print statements in the NavigationObserver callbacks.

    1. MaterialAutoRouter configuration
    Screenshot 2021-04-04 at 22 53 06
    1. Main build function and NavObserver class
    Screenshot 2021-04-04 at 22 53 51 Screenshot 2021-04-04 at 22 54 06
    1. Class to handle bottom navigation
    Screenshot 2021-04-04 at 22 54 45 Screenshot 2021-04-04 at 22 54 57
    1. Logs from NavObserver callbacks (emulator on the right)

    As you can see there are callbacks to the nav observer (simple print statements) for the splash > launch > login > AuthenticatedNavigation routes. However there aren't any logs for routes within the 'AuthenticatedNavigationRoute'. See the second image below, navigated from favourites tab to contacts tab, but nothing registered in the observer.

    Screenshot 2021-04-04 at 22 56 27 Screenshot 2021-04-04 at 22 57 04

    Is there something specific we have to do to observer child routes?

    Thanks for all your work on the library, and apologies if there is something obvious I am missing!

    no-issue-activity 
    opened by rugemo 29
  • AutoRouterObserver and RouteAware

    AutoRouterObserver and RouteAware

    As already described in #486 I plan to fire specific actions on Route change.

    @Milad-Akarie already provided assistance which lead to this example widget

    RouteAwareTest
    class RouteAwareTest extends StatefulWidget {
      RouteAwareTest({Key? key, required this.child}) : super(key: key);
    
      final Widget child;
    
      @override
      _RouteAwareTestState createState() => _RouteAwareTestState();
    }
    
    class _RouteAwareTestState extends State<RouteAwareTest> with RouteAware {
      @override
      void didPopNext() {
        debugPrint('didPopNext');
      }
    
      /// Called when the current route has been pushed.
      @override
      void didPush() {
        debugPrint('didPush');
      }
    
      /// Called when the current route has been popped off.
      @override
      void didPop() {
        debugPrint('didPop');
      }
    
      /// Called when a new route has been pushed, and the current route is no
      /// longer visible.
      @override
      void didPushNext() {
        debugPrint('didPushNext');
      }
    
      @override
      void initState() {
        super.initState();
    
        final AutoRouterObserver? routeObserver =
            RouterScope.of(context)?.firstObserverOfType<AutoRouterObserver>();
    
        final ModalRoute<Object?>? route = ModalRoute.of(context);
        if (routeObserver != null && route != null) {
          routeObserver.subscribe(this, route);  //! <- Error, no 'subscribe' method
        }
      }
    
      @override
      void dispose() {
        // TODO: implement dispose
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return widget.child;
      }
    }
    
    MyApp
    class MyApp extends ConsumerWidget {
      final AppRouter appRouter = AppRouter(authGuard: AuthGuard());
    
      @override
      Widget build(BuildContext context, ScopedReader watch) {
        final bool lightModeEnabled = watch(appThemeStateNotifier);
    
        return MaterialApp.router(
          localizationsDelegates: context.localizationDelegates,
          supportedLocales: context.supportedLocales,
          locale: context.locale,
          theme: AppTheme.lightTheme(context),
          darkTheme: AppTheme.darkTheme(context),
          themeMode: lightModeEnabled ? ThemeMode.light : ThemeMode.dark,
          debugShowCheckedModeBanner: false,
          routerDelegate: appRouter.delegate(
              navigatorObservers: () => <NavigatorObserver>[AutoRouterObserver()]),
          routeInformationParser: appRouter.defaultRouteParser(),
        );
      }
    }
    

    Because of the new AutoRouterObserver I can't run the subscribe method of a RouteObserver. My question now is, how do you build a RouteAware widget that works with the new AutoRouterObserver and fires when the tab changes and routes are pushed/poped.

    P.S. I use auto_route: ^2.1.0

    no-issue-activity 
    opened by jlnrrg 27
  • update analyzer dependency constraints to ^2.0.0

    update analyzer dependency constraints to ^2.0.0

    Looks like auto_route is not compatible with the latest "analyzer" library:

    Because auto_route_generator >=0.6.10 depends on analyzer >=0.40.0 <2.0.0 and json_serializable >=5.0.0 depends on analyzer ^2.0.0

    Please consider update this dependency constraints, thanks.

    no-issue-activity 
    opened by dokinkon 26
  • Reload or refresh the current page

    Reload or refresh the current page

    @Milad-Akarie . When we retry to refresh the current page by refresh button of browser, my application is restarted from the root instead of refreshing the current page.

    opened by prasant10050 0
  • fix: fixed animation duration and jumpTo when animatePageTransition is false

    fix: fixed animation duration and jumpTo when animatePageTransition is false

    Fixed Animation duration and jumpTo when animatePageTransition is false

    Description

    Check issue #1320

    Type of change

    • [X] Bug fix (non-breaking change which fixes an issue)

    How Has This Been Tested?

    Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

    • [ ] Try with an AutoTabsRouter.tabBar with animatePageTransition set as false
    • [ ] Try with an AutoTabsRouter.tabBar with different durations
    • [ ] Try with an AutoTabsRouter.pageView animatePageTransition set as false
    • [ ] Try with an AutoTabsRouter.pageView with different durations
    opened by TheLiux 0
  • [BUG] animatePageTransition won't work when is on false

    [BUG] animatePageTransition won't work when is on false

    Hi! I've found a bug on AutoTabsRouter, when I set animatePageTransition to false, the animation on the transition will persist.

    So i checked on _warpToCurrentIndex() from auto_page_view.dart and i noticed this:

     Future<void> _warpToCurrentIndex() async {
       //stuff
    
       const Duration duration = Duration(milliseconds: 300);
    
        if (duration == Duration.zero) {
           _pageController.jumpToPage(_currentIndex!);
          return Future<void>.value();
        }
    

    As you can see, there are three problems:

    1. Is not possible to enter on the if statement, because the duration is always 300 milliseconds
    2. Is not possible to cannot set a different duration
    3. There isn't any check when animatePageTransition is false

    I don't know if this is expected behaviour or not (but I don't think that is expected), but even on the _warpToCurrentIndex() from auto_tabs_view.dart I also noticed that there isn't animatePageTransition check.

    I did a fix and I will open a PR soon :D Let me know if the code can be improved or if there are mistakes :)

    PS: Happy new year!

    opened by TheLiux 0
  • routeData.queryParams.getBool() etc fail when value is not a string

    routeData.queryParams.getBool() etc fail when value is not a string

    The PageRouteInfo class declares Map<String, dynamic>? queryParams, but setting queryParams: { 'key': true } and trying queryParams.getBool('key') results in a silent crash, because the underlying optBool(String key, [bool? defaultValue]) tries to call _params[key]?.toLowerCase(), which is equal in this case to true.toLowerCase().

    I think replacing _params[key]?.toLowerCase() by _params[key]?.toLowerCase?.call() could fix this issue, although it would be more elegant if getBool() would also work with actual bool values.

    opened by Pwuts 0
  • AutoRouter does not work by default with deep linking from a cold start

    AutoRouter does not work by default with deep linking from a cold start

    I worked with my AutoRouter configurations for a long time and all worked fine with the appRouter.delegate() and the initial route.

    Now as I tested deep linking from a cold start only (!), it always throws a "Can not resolve initial route" in AutoRouter. So I needed to add the initialRoute manually again in the MaterialApp.router() widget even though it is already declared in the router file.

    opened by bennidietz 4
Owner
Milad akarie
Interested in Native Android development, Kotlin, Flutter and Dart.
Milad akarie
Flutter route generator

--- for more docs with examples https://autoroute.vercel.app Introduction Installation Setup and Usage Generated routes Navigation Navigating Between

Milad akarie 1.2k Jan 7, 2023
Startup-Name-Generator-App-in-Flutter - Business Startup Name Generator App in Flutter

Business Startup Name Generator App #About APP: A simple mobile app that generat

AHSAN SIDDZ 0 Jan 30, 2022
Flutter The lightest, easiest and most convenient route management!

Language: English | 中文简体 nav_router nav_router is the simplest / lightweight / convenient routing management solution for flutter. It supports various

FlutterCandies 104 Jan 3, 2023
Fluro is a Flutter routing library that adds flexible routing options like wildcards, named parameters and clear route definitions.

English | Português The brightest, hippest, coolest router for Flutter. Features Simple route navigation Function handlers (map to a function instead

Luke Pighetti 3.5k Jan 4, 2023
Building a simple Flutter app for understanding the BLoC State Management including: Cubit, Managing Route & showSnackBar.

Building a simple Flutter app for understanding the BLoC State Management including: Cubit, Managing Route & showSnackBar.

TAD 8 Dec 3, 2022
Building a simple Flutter app * Switch Theme * for understanding the BLoC State Management including: Cubit Communications with StreamSubscription & Managing Route.

Building a simple Flutter app * Switch Theme * for understanding the BLoC State Management including: Cubit Communications with StreamSubscription & Managing Route.

TAD 1 Oct 3, 2022
Flutter page route transition package, with 62 different transitions

Page Route Animator Package Flutter page route transition package, with 62 different page transitions. Examples Getting Started In the pubspec.yaml of

Mateen Mehmood 10 Nov 24, 2022
Auto route lib - Personal customized use to increase CupertinoRoute transition duration

Auto route lib - Personal customized use to increase CupertinoRoute transition duration , auto route 1.0.0-beta.10 base, so i have to reupload from .pub-cache instead fork it

Mochamad Nizwar Syafuan 0 Jan 4, 2022
Dart and Flutter sealed class generator and annotations, with match methods and other utilities. There is also super_enum compatible API.

Dart Sealed Class Generator Generate sealed class hierarchy for Dart and Flutter. Features Generate sealed class with abstract super type and data sub

6thSolution 15 Jan 2, 2023
Project Structure Auth Generator For Flutter

get_structure_generator Project Structure Auto Generator This is not the package

Mitul Vaghasiya 6 Mar 22, 2022
A Cross-Platform Wisdom Generator built with Flutter

Wisgen ?? A small Cross-Platform Wisdom Generator, built using Flutter and a combination of external APIs This Wisdom Generator combines random advice

Sebastian Faust 31 Dec 6, 2022
FavoriteWords - Random Names Generator Built With Flutter

favorite words The user can select and unselect names, saving the best ones. The

Gülsen Keskin 2 Sep 17, 2022
My-First-Flutter-App - Startup Name Generator App with favorites option

Startup Name Generator App with 'favorites' option.. This is my first Flutter ap

REDLUNA CRYSTAL 0 Jan 21, 2022
Aditya 93 Dec 25, 2022
Asset File Generator For Flutter

A simple command line tool that is used to generate the file containing a class, where all the assets present in the given directory will be mapped to a unique variable name.

null 5 Feb 16, 2022
Adobe XD Flutter Code Generator - Plugin

Adobe XD Flutter Code Generator - Plugin

Giovani Lobato 337 Dec 28, 2022
Code generator for Flutter's theme extension classes.

Welcome to Theme Tailor, a code generator and theming utility for supercharging Flutter ThemeExtension classes introduced in Flutter 3.0! The generato

iteo 35 Jan 2, 2023
A convenient code generator for app styleguide, gallery, wireframes and/or storyboard.

Framy A convenient code generator for app styleguide, gallery, wireframes and/or storyboard. ?? Official documentation ?? Packages In order to use Fra

Fidev 145 Dec 19, 2022
A fully-featured Last.fm client and scrobbler with Shazam-like scrobbling, a collage generator, home screen widgets, and more!

Finale A fully-featured Last.fm client and scrobbler with Shazam-like scrobbling, a collage generator, and more! The app is available on iOS, Android,

Noah Rubin 66 Jan 5, 2023