6

So, I'm using the auto_route package for navigation in my app and flutter_bloc for state management. When I was using the old Navigator, I could just wrap a route with a BlocProvider. For example:

class Router {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (_) => BlocProvider( // wrapped Home with BlocProvider
            create: (context) => SubjectBloc(),
            child: Home(),
          ),
        );
      case '/feed':
        return MaterialPageRoute(builder: (_) => Feed());
    }
  }
}

Now, auto_route uses annotations to generate a routing file. How would I go around providing provider context to the route?

IncorrectMouse
  • 179
  • 1
  • 9

3 Answers3

7

We have our page widget (state/less/ful) implement AutoRouteWrapper

class HomePage extends StatelessWidget implements AutoRouteWrapper{
  .....
 @override
 Widget wrappedRoute(context){
   return BlocProvider(
            create: (context) => HomeBloc(),
            child:  this, // this as the child Important!
          );
   }

}
IncorrectMouse
  • 179
  • 1
  • 9
  • this is scoped I realised – Agyakwalf Apr 28 '22 at 07:00
  • I have `PageTwo` and `PageThree` that accessed through `PageOne`. I implemented `AutoRouteWrapper` in `PageOne`, but why cannot access the bloc inside `PageTwo` and `PageThree`. The error is `Error: Could not find the correct Provider`. – omega_mi Mar 15 '23 at 06:37
  • @IncorrectMouse How we can mock this bloc for this page? – BosS Aug 14 '23 at 07:37
  • @BosS What do you mean by mock? You can provide a bloc/cubit that you'll implement later. – IncorrectMouse Aug 17 '23 at 07:54
  • how we can write widget tests for this page? Here with wrapper we are giving bloc, however in widget test we have to pass MockHomeBloc instead of HomeBloc, how we can achieve this with autorouteWrapper? – BosS Aug 17 '23 at 13:53
7

The answer depends on how your routes are constructed, I'll show you how I achieve this.

For nested routes (When you provide children to your routes), you can use a wrapper. You can wrap your bloc provider(s) around the child and it will provide the bloc to all children screens.

/// routes

AutoRoute(
    page: SupportWrapper,
    name: 'SupportRouter',
    path: 'support',
    children: [
        AutoRoute(
            page: HelpSupportScreen,
            path: '',
        ),
        AutoRoute(
            page: MessageUsScreen,
            path: 'issue',
        ),
    ],
),
/// build method of [support_wrapper.dart]

@override
Widget build(BuildContext context) {
  return MultiBlocProvider(
    providers: [
      BlocProvider(
        create: (context) => _supportCubit,
      ),
    ],
    child: const AutoRouter(),
  );
}

If you are not using a wrapper widget, e.g. its a single screen with no children routes, I would create a separate widget to wrap the BlocProvider around the screen.

class SupportScreen extends StatelessWidget {
  const SupportScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => _supportCubit
      child: const _SupportScreen(),
    );
  }
}

class _SupportScreen extends StatelessWidget {
  const _SupportScreen({Key? key}) : super(key: key);

// rest of your screens code...
mrgnhnt96
  • 3,562
  • 1
  • 17
  • 36
  • That something I tried and it works! The developer of the library suggested that I should implement `AutoRouteWrapper`. – IncorrectMouse Jun 16 '21 at 09:49
  • Great! if you found my answer helpful, don't forget to upvote it or mark it as answered if it answered your question – mrgnhnt96 Jun 16 '21 at 14:19
1

You can also use a custom route builder.

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

@AutoRoute(
  replaceInRouteName: 'Page,Route',
  routes: [
    // ...
    CustomRoute(
      path: '/'
      page: FeedPage
      // ...
      customRouteBuilder: myCustomRouteBuilder,
      // ...
    ),
    // ...
  ]
)

where FeedPage is your the Feed widget. Each page in auto_route should have a pre-defined suffix in its name as you probably already know.

Andres
  • 31
  • 6