title: Flutter Navigator 2.0 Routing via the Navigator()
body: <p>I am currently trying to build a web app with the new Flutter web beta.
  The thing is to be able to have a history, handle the forward and back buttons in the browser and be able to handle user inputs into the URL the new Navigator 2.0 API is required (at least from what I understood).</p>
  <p>There are only a few resources available currently, based on which I am trying to build my Navigator.
  The resources I used:</p>
  <ul>
  <li>(My Main Source)<a href="https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade" rel="noreferrer">'Learning Flutter’s new navigation and routing system'</a> by John Ryan</li>
  <li>A <a href="https://github.com/orestesgaolin/navigator_20_example" rel="noreferrer">similar project</a> (by orestesgaolin) but with a page manager and more complex</li>
  <li>The <a href="https://docs.google.com/document/d/1Q0jx0l4-xymph9O6zLaOY4d_f7YFpNWX_eGbzYxr9wY/edit" rel="noreferrer">publicly shared document by flutter</a> about the new Navigator</li>
  </ul>
  <p>I managed to get the Back and forward button, as well as the history working. However I am struggling to be able to handle the page switches (in the Navigator()). In the example from John he manages the different sites in the 'page: ' array of the Navigator Widget (in the routeDelegater). It seemed strange to me but I tried it like this and it did not really work <em>(Code further down)</em>.</p>
  <p>In the 'page: []' I first tried to have booleans that trigger (like the show404) but that wasn't very clean so my next try was to get the current page as follows (in the array):</p>
  <pre><code>if(_currentPage.name == 'pages[0]') pageBuilds[0]
  </code></pre>
  <p>This kinda worked, as I was then able to type in the segment /matchit/0 and the correct page loaded, however for some reason the '/' route didn't work anymore and I got the error</p>
  <pre><code>Navigator.onGenerateRoute was null, but the route named &quot;/&quot; was referenced 
  </code></pre>
  <p>I then tried to use the 'ongenerateRoute' but that just threw a bunch of errors. I am kinda new so maybe I did something wrong there. But it seemed to me like this was not the correct approach. And this is where I am currently stuck at. I don't know what to try next and am hoping that some of you guys can help me out.</p>
  <p>My Route-Delegater looks as follows (I will include my comments in the code aswell, maybe it helps some of you, who are also looking to understand the Navigator 2.0, understand what is going on):</p>
  <pre><code>/**
   * The RouteDelegate defines application specific behavious of how the router
   * learns about changes in the application state and how it responds to them. 
   * It listens to the RouteInformation Parser and the app state and builds the Navigator with
   * the current list of pages (immutable object used to set navigator's history stack).
   */
  
  //ChangeNotifier for the listeners as they are handled there
  //The popRoute is handled by 'PopNavigatorRouterDelegateMixin'
  class RoutesDelegater extends RouterDelegate&lt;RoutePath&gt;
      with ChangeNotifier, PopNavigatorRouterDelegateMixin&lt;RoutePath&gt; {
    //This is the state of the navigator widget (in build method)
    GlobalKey&lt;NavigatorState&gt; get navigatorKey =&gt; GlobalKey&lt;NavigatorState&gt;();
    //RoutesDelegater()  : navigatorKey = GlobalKey&lt;NavigatorState&gt;();
    MyPage _currentPage;
    bool show404 = false; //checks if we show the 404 page
  
    List&lt;MyPage&gt; pages = [
      MyPage('ProjektListe'),
      MyPage('StudiListe'),
      MyPage('PRView'),
    ];
  
    List&lt;Page&gt; pageBuilds = [
      MaterialPage(key: ValueKey('Unknown'), child: UnknownScreen()),
      MaterialPage(key: ValueKey('Homepage'), child: MyFirstHomepage()),
      MaterialPage(key: ValueKey('OtherScreen'), child: OtherScreen()),
    ];
  
    //currentConfiguration detects changes in the route information
    //It helps complete the browser history and (IMPORTANT) makes the browser back and forward buttons work
  
    RoutePath get currentConfiguration {
      if (show404) {
        return RoutePath.unknown();
      }
      if (_currentPage == null) return RoutePath.home();
      //if not 404 or homepage it is some other page
      return RoutePath.details(pages.indexOf(_currentPage));
    }
  
    @override
    Widget build(BuildContext context) {
      return Navigator(
          key: navigatorKey,
          pages: //List.of(pageBuilds),
              [
            //pageBuilds[1],
            if (show404)
              pageBuilds[0]
            else if (_currentPage != null)
              pageBuilds[1]
          ],
          onPopPage: (route, result) {
            if (!route.didPop(result)) {
              return false;
            }
            _currentPage = null;
            show404 = false;
            //we are using Changenotifier
            notifyListeners();
            return true;
          });
    }
  
    void _handleTapped(MyPage page) {
      _currentPage = page;
      notifyListeners();
    }
  
    @override
    Future&lt;void&gt; setNewRoutePath(RoutePath path) async {
      //Handle the unknown path
      if (path.isUnknown) {
        show404 = true;
        _currentPage = null;
        return;
      }
  
      if (path.isDetailPage) {
        //Check if Path id is valid
        if (path.id.isNegative || path.id &gt; pages.length - 1) {
          show404 = true;
          return;
        }
        _currentPage = pages[path.id];
      } else {
        //homepage will be shown
        _currentPage = null;
      }
  
      show404 = false;
    }
  }
  </code></pre>
  <p>My RoutingInformationParser looks like this:</p>
  <pre><code>/*
  * The RouteInformationParser takes the RouteInformation from RouteInformationProvider and
  * parses it into a user-defined data type.
  */
  
  class MyRoutesInformationParser extends RouteInformationParser&lt;RoutePath&gt; {
    @override
    Future&lt;RoutePath&gt; parseRouteInformation(
        RouteInformation routeInformation) async {
      //routeInformation is an object we get from the uri
      final uri = Uri.parse(routeInformation.location);
      // Handle '/' (Home Path)
      //Path segments are the segments seperated by /, if we don't have any we are on Home
      if (uri.pathSegments.length == 0) {
        return RoutePath.home();
      }
  
      //We have 2, as we have matchit/...
      if (uri.pathSegments.length == 2) {
        //If there is no 'matchit' in the first path segment the path is unknown
        if (uri.pathSegments.first != 'matchit') return RoutePath.unknown();
        //If we now have the correct first segment we can now handle the rest of the segment
        final remaining = uri.pathSegments.elementAt(1);
        final id = int.tryParse(remaining);
        //if it fails we return the unknown path
        if (id == null) return RoutePath.unknown();
        return RoutePath.details(id);
      }
  
      //Handling the unknown Path, e.g. user just typed anything in uri
      return RoutePath.unknown();
    }
  
    //THIS IS IMPORTANT: Here we restore the web history
    @override
    RouteInformation restoreRouteInformation(RoutePath path) {
      //Here we set the routeInformation which is used above, e.g. /404 for unknown page
      if (path.isUnknown) {
        return RouteInformation(location: '/404');
      }
      if (path.isHomePage) {
        return RouteInformation(location: '/');
      }
      //Any other page is handled here via /matchit/... &lt;= the id of the path
      if (path.isDetailPage) {
        return RouteInformation(location: '/matchit/${path.id}');
      }
      //If none of the paths are hit
      return null;
    }
  }
  </code></pre>
  <p>Then we also have my Data-type for the routing information:</p>
  <pre><code>class RoutePath{
    final int id;
    final bool isUnknown;
  
    RoutePath.home()
        : id = null,
          isUnknown = false;
  
    //Details means here that it is any other side than Home or unknown
    RoutePath.details(this.id) : isUnknown = false;
  
    RoutePath.unknown()
        : id = null,
          isUnknown = true;
  
    //check if is on HomePage or other page, then either == null or != null
    //not needed for isInknown, as when unknown then = true as set above
    bool get isHomePage =&gt; id == null;
    bool get isDetailPage =&gt; id != null;
  }
  </code></pre>
  <p>An lastly my Homepage() where the InformationParser and Delegater are initialized:</p>
  <pre><code>class Homepage extends StatefulWidget {
    @override
    State&lt;StatefulWidget&gt; createState() =&gt; _HomepageState();
  }
  
  class _HomepageState extends State&lt;Homepage&gt; {
    //initialize the RouteDelegater and Information Parser to be unsed further down
  
    RoutesDelegater _routesDelegater = RoutesDelegater();
    MyRoutesInformationParser _myRoutesInformationParser =
        MyRoutesInformationParser();
  
  /*
   * Relevant routing information for this build method:
   * We need to use the MaterialApp.router else we can't use routerDelegate and routeInformationParser.
   * Then we define the delegate and Information Parser (they are initiated above)
   */
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp.router(
          title: 'MatchIT',
          routerDelegate: _routesDelegater,
          routeInformationParser: _myRoutesInformationParser,
          theme: ThemeData(primarySwatch: Colors.blue),
          debugShowCheckedModeBanner: false);
    }
  }
  </code></pre>
  <p>Thank you in advance!</p>