Flutter Web and Navigation History
Tags: flutter, dart, webdev, productivity
Published: 2020-09-26 10:08:27

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:paragraph -->
<p><strong><em>Website: </em></strong><a href="https://web.flatteredwithflutter.com/#/" rel="noreferrer noopener" target="_blank"><strong><em>https://web.flatteredwithflutter.com/#/</em></strong></a></p>
<!-- /wp:paragraph -->

{% youtube 05Eeum2QMkc %}

<!-- wp:paragraph -->
<p>We will cover briefly about</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Storing navigation routes</li><li>Implement navigatorObservers</li></ol>
<!-- /wp:list -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

####Article here: https://flatteredwithflutter.com/flutter-web-and-navigation-history/

<!-- wp:heading {"level":4} -->
<h4>1. Storing navigation routes</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>It's quite clear, we need a data structure for storing routes.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Thought process</strong>: When we navigate between different links in a browser, the last link is usually the first to be traced back (<strong>on click of the back button</strong>).</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1200/1*wobnLwSj_PMLYN19Ov0Vfg.png" alt=""/><figcaption>Flutter Web and Navigation History</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><strong>Going 1 link to several</strong></p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>You navigate to link A</li><li>After a while, you go to link B</li><li>Finally, you end up at the link C</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>(Note: This assumes you are in 1 single tab only)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>On backtracking</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1200/1*stIEIZaPxYmng_k9slrJCQ.png" alt=""/><figcaption>Flutter Web and Navigation History</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><strong>Going back now</strong></p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>You start backtrack from link C</li><li>You go to link B</li><li>Finally, you end up at the link A</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>(Note: This assumes you are in 1 single tab only)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The data structure right for use would be <strong>Stack </strong>since we need to <strong>push</strong> the routes onto the stack and <strong>pop</strong> (when we go back to the previous link).</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*ec4ctPaUobpyIflt36E-2w.png" alt=""/><figcaption>Stack — Push, pop,&nbsp;top</figcaption></figure>
<!-- /wp:image -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:heading {"level":4} -->
<h4>Implementing Stacks in&nbsp;Dart</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In doing my research I found</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted"><a href="https://api.dart.dev/stable/2.9.3/dart-collection/dart-collection-library.html" rel="noreferrer noopener" target="_blank">dart:collection</a></pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>As per the documentation:</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Classes and utilities that supplement the collection support in dart:core.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>But did not find any explicit collection named Stack, until I stumbled upon <a href="https://api.dart.dev/stable/2.9.3/dart-collection/ListQueue-class.html" rel="noreferrer noopener" target="_blank"><strong>ListQueue</strong></a></p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>List based <a href="https://api.dart.dev/stable/2.9.3/dart-collection/Queue-class.html" rel="noreferrer noopener" target="_blank">Queue</a>.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Keeps a cyclic buffer of elements, and grows to a larger buffer when it fills up. This guarantees constant time peek and remove operations, and amortized constant time add operations.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><strong>The structure is efficient for any queue or stack usage</strong>.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>We will use ListQueue for storing our routes.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Implementing ListQueue for storing&nbsp;routes</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We make an abstract class first, to define the operations which we will implement for our generic ListQueue.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">abstract class _NavStack&lt;T> {
  void push(T val) {}
  void pop() {}
  T top();
  List&lt;T> fetchAll();
  void get clear {}
}</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p><strong>push</strong>: For pushing a route of type T</p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:paragraph -->
<p><strong>pop</strong>: For popping the route (topmost)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>top</strong>: Get the route which is on top</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>fetchAll</strong>: Get all the routes saved.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>clear</strong>: Clear the saved routes</p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:paragraph -->
<p>Let’s define our class(<strong>NavStack</strong>) which implements the above abstract class(<strong>_NavStack</strong>).</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">class NavStack&lt;T&gt; implements _NavStack&lt;T&gt; {}</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>Initialize the list queue by</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">final ListQueue&lt;T&gt; _internal = ListQueue();</pre>
<!-- /wp:preformatted -->

<!-- wp:heading {"level":4} -->
<h4>Pushing item</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pushing items in this list by using the <a rel="noreferrer noopener" href="https://api.dart.dev/stable/2.9.3/dart-collection/ListQueue/addLast.html" target="_blank"><strong>addLast</strong></a> function of the list queue.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">_internal.addLast('SOME VALUE');</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p><strong>addLast</strong>: Adds the items at the end. Since each new route will be the latest, we add it to the end of the list queue.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Popping item</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pop the item in this list by using <a href="https://api.dart.dev/stable/2.9.3/dart-collection/ListQueue/removeLast.html" rel="noreferrer noopener" target="_blank"><strong>removeLast</strong></a> function of the list queue.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">_internal.removeLast();</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p><strong>removeLast</strong>: Removes and returns the last element of the queue.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Top item</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Getting the topmost or latest item in this list queue by the <a href="https://api.dart.dev/stable/2.9.3/dart-collection/ListQueue/last.html" rel="noreferrer noopener" target="_blank"><strong>last</strong></a> function</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">_internal.last;</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p><strong>last</strong>: Returns the last (or topmost) element. Meaning our latest route is always at the top of the stack.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Clearing and Fetching&nbsp;items</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We will use the <a href="https://api.dart.dev/stable/2.9.3/dart-collection/ListQueue/clear.html" rel="noreferrer noopener" target="_blank"><strong>clear</strong></a> function of the list queue for clearing our stored routes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For fetching items, we will loop through the length of the list, add items to a new list and return.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">List&lt;T> fetchAll() {
  final _list = &lt;T>[];
  
  for (var i = 0; i &lt; length; i++) {
    _list.add(_internal.elementAt(i));
  }
 
  return _list;
}</pre>
<!-- /wp:preformatted -->

<!-- wp:heading {"level":4} -->
<h4>2. Implement Navigator Observers</h4>
<!-- /wp:heading -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*_q6vCvDVvgP2Tck6FOjm5A.png" alt=""/><figcaption>Flutter Web and Navigation History&nbsp;(Output)</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>We have the list queue implemented from the above step.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Next, we need to place this list queue in our flutter web, in such a way that </p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>whenever a new route is pushed,</li><li>it should also be added to our <strong>NavStack</strong> class</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>There is a property inside MaterialApp called <a href="https://api.flutter.dev/flutter/widgets/NavigatorObserver-class.html" rel="noreferrer noopener" target="_blank"><strong>navigatorObservers</strong></a><strong>. </strong>This implements RouteObserver internally.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>RouteObserver</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p><a href="https://api.flutter.dev/flutter/widgets/RouteObserver-class.html" rel="noreferrer noopener" target="_blank">RouteObserver</a> informs subscribers whenever a route of type <code>R</code> is pushed on top of their own route of type <code>R</code> or popped from it.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>e.g. a <code>RouteObserver&lt;PageRoute&gt;</code> will inform subscribed <a href="https://api.flutter.dev/flutter/widgets/RouteAware-class.html" rel="noreferrer noopener" target="_blank">RouteAware</a>s&nbsp;</li><li>whenever the user navigates away from the current page route to another page route.</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Methods inside RouteObserver class</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><code>didPop</code> (whenever a route is popped)</li><li><code>didPush</code> (whenever a route is pushed)</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>We will create our own navigator observers which</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>extends the RouteObserver</li><li>implements the <code>didPop</code> and <code>didPush</code> methods</li></ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*3Zx--6Ww4eT3UNW2vnh_-g.png" alt=""/><figcaption>Flutter Web and Navigation History</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>Inside the <code>didPush</code>we extract the current screen name and push it into our <strong>NavStack</strong> class. This way whenever a route is pushed, it also gets added to our class.</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Finally, we add this custom navigator observer to MaterialApp’s property.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">return MaterialApp(
  // OTHER PROPERTIES
  navigatorObservers: [CustomRouteObserver()],
);</pre>
<!-- /wp:preformatted -->

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

{% youtube 05Eeum2QMkc %}

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Hosted URL&nbsp;: <a href="https://web.flatteredwithflutter.com/#/" rel="noreferrer noopener" target="_blank">https://web.flatteredwithflutter.com/#/</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><a href="https://github.com/AseemWangoo/experiments_with_web" rel="noreferrer noopener" target="_blank">Source code for Flutter Web App..</a></p></blockquote>
<!-- /wp:quote -->