0

StackOverflow community!

What I'm trying to build is a mobile/web application in Flutter with a static "always open" drawer on the web.

So what I did is I've created and router (with Fluro) and use it in the onGenerateRoute function of my MaterialApp. The child will be created from the router and I'll pass it to the "MainLayout".

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'MyApp',
      theme: appTheme,
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        FlutterI18nDelegate(
          translationLoader: FileTranslationLoader(
              basePath: 'assets/i18n',
              fallbackFile: 'de_DE',
              useCountryCode: true),
        ),
      ],
      supportedLocales: [
        const Locale('en', 'US'), // English
        const Locale('de', 'DE'), // German
      ],
      initialRoute: NavUtils.initialUrl,
      onGenerateRoute: router.generator,
      navigatorKey: _navigatorKey,
      builder: (context, child) {
        return MultiBlocProvider(
          providers: [
            BlocProvider.value(
              value: _authenticationBloc,
            ),
            BlocProvider.value(
              value: _userSettingsBloc,
            ),
            BlocProvider.value(
              value: _organizationBloc,
            ),
            BlocProvider.value(
              value: _reportsBloc,
            ),
          ],
          child: BlocBuilder<AuthenticationBloc, AuthenticationState>(
            builder: (context, state) {
              if (state is AuthenticationAuthenticated) {
                return MainLayout(
                  child: child,
                  drawerKey: _drawerKey,
                  navigatorKey: _navigatorKey,
                );
              } else {
                return Scaffold(
                  backgroundColor: mainBackground,
                  drawer: DrawerMenu(
                    navigatorKey: _navigatorKey,
                    drawerKey: _drawerKey,
                  ),
                  body: SafeArea(
                    child: child,
                  ),
                );
              }
            },
          ),
        );
      },
    );
  }

and the content of my MainLayout()

class MainLayout extends StatelessWidget {
  final Widget child;
  final GlobalKey<ScaffoldState> drawerKey;
  final GlobalKey<NavigatorState> navigatorKey;
  MainLayout(
      {Key key,
      @required this.child,
      @required this.drawerKey,
      @required this.navigatorKey})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: drawerKey,
      backgroundColor: mainBackground,
      drawer: MediaQuery.of(context).size.width >= 769
          ? null
          : DrawerMenu(
              navigatorKey: navigatorKey,
              drawerKey: drawerKey,
            ),
      body: SafeArea(
        child: Container(
          child: Row(
            children: <Widget>[
              MediaQuery.of(context).size.width >= 769
                  ? DrawerMenu(
                      navigatorKey: navigatorKey,
                      drawerKey: drawerKey,
                    )
                  : Container(),
              Expanded(
                child: child,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

The problem I have is, that ie. my DrawerMenu() can't find the navigator in the context. Leading me to problems like I can't use any tooltip widget because it's not finding the overlay.

════════ Exception caught by widgets library ═══════════════════════════════════
No Overlay widget found.
The relevant error-causing widget was
    Tooltip 

As soon as I'll wrap my whole MaterialApp in another MaterialApp it's working fine, but I destroy my routing.

Can anybody help me with this? Is this enough information to even provide any help?


Update

With your question and your answer here on StackOverflow I figured out, that I have to use this different. What I did is to "extract" the whole stuff and make created a Navigator in the Scaffold, like this:

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'MyApp',
      theme: appTheme,
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        FlutterI18nDelegate(
          translationLoader: FileTranslationLoader(
              basePath: 'assets/i18n',
              fallbackFile: 'de_DE',
              useCountryCode: true),
        ),
      ],
      supportedLocales: [
        const Locale('en', 'US'), // English
        const Locale('de', 'DE'), // German
      ],
      initialRoute: NavUtils.initialUrl,
      onGenerateRoute: (RouteSettings settings) {
        _navigatorKey.currentState.popAndPushNamed(settings.name);
      },
      home: Builder(
        builder: (context) => MultiBlocProvider(
          providers: [
            BlocProvider.value(
              value: _authenticationBloc,
            ),
            BlocProvider.value(
              value: _userSettingsBloc,
            ),
            BlocProvider.value(
              value: _organizationBloc,
            ),
            BlocProvider.value(
              value: _reportsBloc,
            ),
          ],
          child: Scaffold(
            key: _drawerKey,
            backgroundColor: mainBackground,
            drawer: MediaQuery.of(context).size.width >= 769
                ? null
                : DrawerMenu(
                    navigatorKey: _navigatorKey,
                    drawerKey: _drawerKey,
                  ),
            body: SafeArea(
              child: Container(
                child: Row(
                  children: <Widget>[
                    MediaQuery.of(context).size.width >= 769
                        ? DrawerMenu(
                            navigatorKey: _navigatorKey,
                            drawerKey: _drawerKey,
                          )
                        : Container(),
                    Expanded(
                      child: Navigator(
                        key: _navigatorKey,
                        initialRoute: NavUtils.initialUrl,
                        onGenerateRoute: router.generator,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

The only problem now is, how do I get the URL, a user enters in the browser address bar, to my navigator.

For now I'm using _navigatorKey.currentState.popAndPushNamed(settings.name); in my MaterialApp but this removes the URL in the address bar after hitting enter. (But it actually navigates to the correct page)

Is there a way to keep this consistent?

Aerofluxx
  • 61
  • 1
  • 6
  • Why did you use the "builder" argument of MaterialApp here? It doesn't have access to Navigator – Rémi Rousselet Apr 21 '20 at 12:51
  • @RémiRousselet I thought that it will build the child from the onGenerateRoute and pass it to the MainLayout(). Is this not correct? – Aerofluxx Apr 21 '20 at 12:53
  • That's not the case no. `builder` is here to replace `Navigator`. – Rémi Rousselet Apr 21 '20 at 14:12
  • @RémiRousselet Oh well. Then I got this completely wrong. I've updated my request above with this information. Is this the right way to a static drawer and switching content you think? – Aerofluxx Apr 21 '20 at 14:17

0 Answers0