Widgets

Navigation Hub



Introduction

Navigation Hubs are a central place where you can manage the navigation for all your widgets. Out the box you can create bottom, top and journey navigation layouts in seconds.

Let's imagine you have an app and you want to add a bottom navigation bar and allow users to navigate between different tabs in your app.

You can use a Navigation Hub to build this.

Let's dive into how you can use a Navigation Hub in your app.


Basic Usage

You can create a Navigation Hub using the below command.

dart run nylo_framework:main make:navigation_hub base
// or with Metro
metro make:navigation_hub base

This will create a base_navigation_hub.dart file in your resources/pages/ directory.

import 'package:flutter/material.dart';
import 'package:nylo_framework/nylo_framework.dart';

class BaseNavigationHub extends NyStatefulWidget with BottomNavPageControls {
  static RouteView path = ("/base", (_) => BaseNavigationHub());
  
  BaseNavigationHub()
      : super(
            child: () => _BaseNavigationHubState(),
            stateName: path.stateName());

  /// State actions
  static NavigationHubStateActions stateActions = NavigationHubStateActions(path.stateName());
}

class _BaseNavigationHubState extends NavigationHub<BaseNavigationHub> {

  /// Layouts: 
  /// - [NavigationHubLayout.bottomNav] Bottom navigation
  /// - [NavigationHubLayout.topNav] Top navigation
  /// - [NavigationHubLayout.journey] Journey navigation
  NavigationHubLayout? layout = NavigationHubLayout.bottomNav(
    // backgroundColor: Colors.white,
  );

  /// Should the state be maintained
  @override
  bool get maintainState => true;

  /// Navigation pages
  _BaseNavigationHubState() : super(() async {
    return {
      0: NavigationTab(
        title: "Home",
        page: HomeTab(),
        icon: Icon(Icons.home),
        activeIcon: Icon(Icons.home),
      ),
      1: NavigationTab(
         title: "Settings",
         page: SettingsTab(),
         icon: Icon(Icons.settings),
         activeIcon: Icon(Icons.settings),
      ),
    };
  });
}

You can see that the Navigation Hub has two tabs, Home and Settings.

You can create more tabs by adding NavigationTab's to the Navigation Hub.

First, you need to create a new widget using Metro.

dart run nylo_framework:main make:stateful_widget create_advert_tab
// or with Metro
metro make:stateful_widget create_advert_tab

You can also create multiple widgets at once.

dart run nylo_framework:main make:stateful_widget news_tab,notifications_tab
// or with Metro
metro make:stateful_widget news_tab,notifications_tab

Then, you can add the new widget to the Navigation Hub.

  _BaseNavigationHubState() : super(() async {
    return {
      0: NavigationTab(
        title: "Home",
        page: HomeTab(),
        icon: Icon(Icons.home),
        activeIcon: Icon(Icons.home),
      ),
      1: NavigationTab(
         title: "Settings",
         page: SettingsTab(),
         icon: Icon(Icons.settings),
         activeIcon: Icon(Icons.settings),
      ),
      2: NavigationTab(
         title: "News",
         page: NewsTab(),
         icon: Icon(Icons.newspaper),
         activeIcon: Icon(Icons.newspaper),
      ),
    };
  });

import 'package:nylo_framework/nylo_framework.dart';

appRouter() => nyRoutes((router) {
    ...
    router.add(BaseNavigationHub.path).initalRoute();
});

// or navigate to the Navigation Hub from anywhere in your app

routeTo(BaseNavigationHub.path);

There's a lot more you can do with a Navigation Hub, let's dive into some of the features.


Bottom Navigation

You can change the layout to a bottom navigation bar by setting the layout to use NavigationHubLayout.bottomNav.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.bottomNav();

You can customize the bottom navigation bar by setting properties like the following:

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.bottomNav(
        // customize the bottomNav layout properties
    );

Top Navigation

You can change the layout to a top navigation bar by setting the layout to use NavigationHubLayout.topNav.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.topNav();

You can customize the top navigation bar by setting properties like the following:

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.topNav(
        // customize the topNav layout properties
    );

Journey Navigation

You can change the layout to a journey navigation by setting the layout to use NavigationHubLayout.journey.

This is great for onboarding flows or multi-step forms.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.journey(
        // customize the journey layout properties
    );

If you want to use the journey navigation layout, your widgets should use JourenyState as it contains a lot of helper methods to help you manage the journey.

You can create a JourneyState using the below command.

dart run nylo_framework:main make:journey_widget welcome,phone_number_step,add_photos_step
// or with Metro
metro make:journey_widget welcome,phone_number_step,add_photos_step

This will create the following files in your resources/widgets/ directory welcome.dart, phone_number_step.dart and add_photos_step.dart.

You can then add the new widgets to the Navigation Hub.

_MyNavigationHubState() : super(() async {
    return {
        0: NavigationTab.journey(
            page: Welcome(),
        ),
        1: NavigationTab.journey(
            page: PhoneNumberStep(),
        ),
        2: NavigationTab.journey(
            page: AddPhotosStep(),
        ),
    };
});

The journey navigation layout will automatically handle the back and next buttons for you if you define a buttonStyle.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.journey(
        buttonStyle: JourneyButtonStyle.standard(
            // Customize button properties
        ),
    );

You can also customize the logic in your widgets.

import 'package:flutter/material.dart';
import '/resources/pages/onboarding_navigation_hub.dart';
import '/resources/widgets/buttons/buttons.dart';
import 'package:nylo_framework/nylo_framework.dart';

class WelcomeStep extends StatefulWidget {
  const WelcomeStep({super.key});

  @override
  createState() => _WelcomeStepState();
}

class _WelcomeStepState extends JourneyState<WelcomeStep> {
  _WelcomeStepState() : super(
      navigationHubState: OnboardingNavigationHub.path.stateName());

  @override
  get init => () {
    // Your initialization logic here
  };

  @override
  Widget view(BuildContext context) {
    return buildJourneyContent(
      content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('WelcomeStep', style: Theme.of(context).textTheme.headlineMedium),
          const SizedBox(height: 20),
          Text('This onboarding journey will help you get started.'),
        ],
      ),
      nextButton: Button.primary(
        text: isLastStep ? "Get Started" : "Continue",
        onPressed: onNextPressed,
      ),
      backButton: isFirstStep ? null : Button.textOnly(
        text: "Back",
        textColor: Colors.black87,
        onPressed: onBackPressed,
      ),
    );
  }

  /// Check if the journey can continue to the next step
  /// Override this method to add validation logic
  Future<bool> canContinue() async {
    // Perform your validation logic here
    // Return true if the journey can continue, false otherwise
    return true;
  }

  /// Called when unable to continue (canContinue returns false)
  /// Override this method to handle validation failures
  Future<void> onCannotContinue() async {
    showToastSorry(description: "You cannot continue");
  }

  /// Called before navigating to the next step
  /// Override this method to perform actions before continuing
  Future<void> onBeforeNext() async {
    // E.g. save data here before navigating
  }

  /// Called after navigating to the next step
  /// Override this method to perform actions after continuing
  Future<void> onAfterNext() async {
    // print('Navigated to the next step');
  }

  /// Called when the journey is complete (at the last step)
  /// Override this method to perform completion actions
  Future<void> onComplete() async {}
}

You can override any of the methods in the JourneyState class.


Journey Progress Styles

You can customize the progress indicator style by using the JourneyProgressStyle class.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.journey(
        progressStyle: JourneyProgressStyle.linear(
            activeColor: Colors.blue,
            inactiveColor: Colors.grey,
            thickness: 4.0,
        ),
    );

You can use the following progress styles:

  • JourneyProgressStyle.linear: Linear progress indicator.
  • JourneyProgressStyle.dots: Dots-based progress indicator.
  • JourneyProgressStyle.numbered: Numbered step progress indicator.
  • JourneyProgressStyle.segments: Segmented progress bar style.
  • JourneyProgressStyle.circular: Circular progress indicator.
  • JourneyProgressStyle.timeline: Timeline-style progress indicator.
  • JourneyProgressStyle.custom: Custom progress indicator using a builder function.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.journey(
        progressStyle: JourneyProgressStyle.custom(
            builder: (context, currentStep, totalSteps, percentage) {
                return LinearProgressIndicator(
                    value: percentage,
                    backgroundColor: Colors.grey[200],
                    color: Colors.blue,
                    minHeight: 4.0,
                );
            },
        ),
    );

You can also customize the progress indicator position by using the progressIndicatorPosition property.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.journey(
        progressIndicatorPosition: ProgressIndicatorPosition.top,
    );

You can use the following progress indicator positions:

  • ProgressIndicatorPosition.top: Progress indicator at the top of the screen.
  • ProgressIndicatorPosition.bottom: Progress indicator at the bottom of the screen.

You can also customize the progress indicator padding by using the progressIndicatorPadding property.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.journey(
        progressIndicatorPadding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
    );

Journey Button Styles

If you want to build an onboarding flow, you can set the buttonStyle property in the NavigationHubLayout.journey class.

Out the box, you can use the following button styles:

  • JourneyButtonStyle.standard: Standard button style with customizable properties.
  • JourneyButtonStyle.minimal: Minimal button style with icons only.
  • JourneyButtonStyle.outlined: Outlined button style.
  • JourneyButtonStyle.contained: Contained button style.
  • JourneyButtonStyle.custom: Custom button style using builder functions.
class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.journey(
        progressStyle: JourneyProgressStyle.linear(),
        buttonStyle: JourneyButtonStyle.standard(
            // Customize button properties
        ),
    );

JourneyState

The JourneyState class contains a lot of helper methods to help you manage the journey.

To create a new JourneyState, you can use the below command.

dart run nylo_framework:main make:journey_widget onboard_user_dob

Or if you want to create multiple widgets at once, you can use the following command.

dart run nylo_framework:main make:journey_widget welcome,phone_number_step,add_photos_step

This will create the following files in your resources/widgets/ directory welcome.dart, phone_number_step.dart and add_photos_step.dart.

You can then add the new widgets to the Navigation Hub.

_MyNavigationHubState() : super(() async {
    return {
        0: NavigationTab.journey(
            page: Welcome(),
        ),
        1: NavigationTab.journey(
            page: PhoneNumberStep(),
        ),
        2: NavigationTab.journey(
            page: AddPhotosStep(),
        ),
    };
});

If we look at the WelcomeStep class, we can see that it extends the JourneyState class.

...
class _WelcomeTabState extends JourneyState<WelcomeTab> {
  _WelcomeTabState() : super(
      navigationHubState: BaseNavigationHub.path.stateName());

  @override
  get init => () {
    // Your initialization logic here
  };

  @override
  Widget view(BuildContext context) {
    return buildJourneyContent(
      progressStyle: JourneyProgressStyle.dots(
        activeColor: Colors.red
      ),
      content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('WelcomeTab', style: Theme.of(context).textTheme.headlineMedium),
          const SizedBox(height: 20),
          Text('This onboarding journey will help you get started.'),
        ],
      ),
    );
  }

You'll notice that the JourneyState class will use buildJourneyContent to build the content of the page.

Here are a list of the properties you can use in the buildJourneyContent method.

Property Type Description
content Widget The main content of the page.
nextButton Widget? The next button widget.
backButton Widget? The back button widget.
progressPosition ProgressIndicatorPosition The position of the progress indicator.
progressStyle JourneyProgressStyle? The style of the progress indicator.
contentPadding EdgeInsetsGeometry The padding for the content.
progressIndicatorPadding EdgeInsets? The padding for the progress indicator.
header Widget? The header widget.
footer Widget? The footer widget.
crossAxisAlignment CrossAxisAlignment The cross axis alignment of the content.

JourneyState Helper Methods

The JourneyState class has some helper methods that you can use to customize the behavior of your journey.

Method Description
onNextPressed() Called when the next button is pressed.
onBackPressed() Called when the back button is pressed.
onComplete() Called when the journey is complete (at the last step).
onBeforeNext() Called before navigating to the next step.
onAfterNext() Called after navigating to the next step.
onCannotContinue() Called when the journey cannot continue (canContinue returns false).
canContinue() Called when the user tries to navigate to the next step.
isFirstStep Returns true if this is the first step in the journey.
isLastStep Returns true if this is the last step in the journey.
goToStep(int index) Navigate to the next step index.
goToNextStep() Navigate to the next step.
goToPreviousStep() Navigate to the previous step.
goToFirstStep() Navigate to the first step.
goToLastStep() Navigate to the last step.

onNextPressed

The onNextPressed method is called when the next button is pressed.

E.g. You can use this method to trigger the next step in the journey.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        nextButton: Button.primary(
            text: isLastStep ? "Get Started" : "Continue",
            onPressed: onNextPressed, // this will attempt to navigate to the next step
        ),
    );
}

onBackPressed

The onBackPressed method is called when the back button is pressed.

E.g. You can use this method to trigger the previous step in the journey.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        backButton: isFirstStep ? null : Button.textOnly(
            text: "Back",
            textColor: Colors.black87,
            onPressed: onBackPressed, // this will attempt to navigate to the previous step
        ),
    );
}

onComplete

The onComplete method is called when the journey is complete (at the last step).

E.g. if the if this widget is the last step in the journey, this method will be called.

Future<void> onComplete() async {
    print("Journey completed");
}

onBeforeNext

The onBeforeNext method is called before navigating to the next step.

E.g. if you want to save data before navigating to the next step, you can do it here.

Future<void> onBeforeNext() async {
    // E.g. save data here before navigating
}

isFirstStep

The isFirstStep method returns true if this is the first step in the journey.

E.g. You can use this method to disable the back button if this is the first step.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        backButton: isFirstStep ? null : Button.textOnly( // Example of disabling the back button
            text: "Back",
            textColor: Colors.black87,
            onPressed: onBackPressed,
        ),
    );
}

isLastStep

The isLastStep method returns true if this is the last step in the journey.

E.g. You can use this method to disable the next button if this is the last step.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        nextButton: Button.primary(
            text: isLastStep ? "Get Started" : "Continue", // Example updating the next button text
            onPressed: onNextPressed,
        ),
    );
}

goToStep

The goToStep method is used to navigate to a specific step in the journey.

E.g. You can use this method to navigate to a specific step in the journey.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        nextButton: Button.primary(
            text: "Add photos"
            onPressed: () {
                goToStep(2); // this will navigate to the step with index 2
                // Note: this will not trigger the onNextPressed method
            }, 
        ),
    );
}

goToNextStep

The goToNextStep method is used to navigate to the next step in the journey.

E.g. You can use this method to navigate to the next step in the journey.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        nextButton: Button.primary(
            text: "Continue",
            onPressed: () {
                goToNextStep(); // this will navigate to the next step
                // Note: this will not trigger the onNextPressed method
            }, 
        ),
    );
}

goToPreviousStep

The goToPreviousStep method is used to navigate to the previous step in the journey.

E.g. You can use this method to navigate to the previous step in the journey.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        backButton: isFirstStep ? null : Button.textOnly(
            text: "Back",
            textColor: Colors.black87,
            onPressed: () {
                goToPreviousStep(); // this will navigate to the previous step
            }, 
        ),
    );
}

onAfterNext

The onAfterNext method is called after navigating to the next step.

E.g. if you want to perform some action after navigating to the next step, you can do it here.

Future<void> onAfterNext() async {
    // print('Navigated to the next step');
}

onCannotContinue

The onCannotContinue method is called when the journey cannot continue (canContinue returns false).

E.g. if you want to show an error message when the user tries to navigate to the next step without filling in the required fields, you can do it here.

Future<void> onCannotContinue() async {
    showToastSorry(description: "You cannot continue");
}

canContinue

The canContinue method is called when the user tries to navigate to the next step.

E.g. if you want to perform some validation before navigating to the next step, you can do it here.

Future<bool> canContinue() async {
    // Perform your validation logic here
    // Return true if the journey can continue, false otherwise
    return true;
}

goToFirstStep

The goToFirstStep method is used to navigate to the first step in the journey.

E.g. You can use this method to navigate to the first step in the journey.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        nextButton: Button.primary(
            text: "Continue",
            onPressed: () {
                goToFirstStep(); // this will navigate to the first step
            }, 
        ),
    );
}

goToLastStep

The goToLastStep method is used to navigate to the last step in the journey.

E.g. You can use this method to navigate to the last step in the journey.

@override
Widget view(BuildContext context) {
    return buildJourneyContent(
        content: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
                ...
            ],
        ),
        nextButton: Button.primary(
            text: "Continue",
            onPressed: () {
                goToLastStep(); // this will navigate to the last step
            }, 
        ),
    );
}

Navigating to widgets within a tab

You can navigate to widgets within a tab by using the pushTo helper.

Inside your tab, you can use the pushTo helper to navigate to another widget.

_HomeTabState extends State<HomeTab> {
    ...
    void _navigateToSettings() {
        pushTo(SettingsPage());
    }
    ...
}

You can also pass data to the widget you're navigating to.

_HomeTabState extends State<HomeTab> {
    ...
    void _navigateToSettings() {
        pushTo(SettingsPage(), data: {"name": "Anthony"});
    }
    ...
}

Tabs

Tabs are the main building blocks of a Navigation Hub.

You can add tabs to a Navigation Hub by using the NavigationTab class.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.bottomNav();
    ... 
    _MyNavigationHubState() : super(() async {
        return {
            0: NavigationTab(
                title: "Home",
                page: HomeTab(),
                icon: Icon(Icons.home),
                activeIcon: Icon(Icons.home),
            ),
            1: NavigationTab(
                title: "Settings",
                page: SettingsTab(),
                icon: Icon(Icons.settings),
                activeIcon: Icon(Icons.settings),
            ),
        };
    });

In the above example, we've added two tabs to the Navigation Hub, Home and Settings.

You can use different kinds of tabs like NavigationTab, NavigationTab.badge, and NavigationTab.alert.

  • The NavigationTab.badge class is used to add badges to tabs.
  • The NavigationTab.alert class is used to add alerts to tabs.
  • The NavigationTab class is used to add a normal tab.

Adding Badges to Tabs

We've made it easy to add badges to your tabs.

Badges are a great way to show users that there's something new in a tab.

Example, if you have a chat app, you can show the number of unread messages in the chat tab.

To add a badge to a tab, you can use the NavigationTab.badge class.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.bottomNav();
    ... 
    _MyNavigationHubState() : super(() async {
        return {
            0: NavigationTab.badge(
                title: "Chats",
                page: ChatTab(),
                icon: Icon(Icons.message),
                activeIcon: Icon(Icons.message),
                initialCount: 10,
            ),
            1: NavigationTab(
                title: "Settings",
                page: SettingsTab(),
                icon: Icon(Icons.settings),
                activeIcon: Icon(Icons.settings),
            ),
        };
    });

In the above example, we've added a badge to the Chat tab with an initial count of 10.

You can also update the badge count programmatically.

/// Increment the badge count
BaseNavigationHub.stateActions.incrementBadgeCount(tab: 0);

/// Update the badge count
BaseNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 5);

/// Clear the badge count
BaseNavigationHub.stateActions.clearBadgeCount(tab: 0);

By default, the badge count will be remembered. If you want to clear the badge count each session, you can set rememberCount to false.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.bottomNav();
    ... 
    _MyNavigationHubState() : super(() async {
        return {
            0: NavigationTab.badge(
                title: "Chats",
                page: ChatTab(),
                icon: Icon(Icons.message),
                activeIcon: Icon(Icons.message),
                initialCount: 10,
                rememberCount: false,
            ),
            1: NavigationTab(
                title: "Settings",
                page: SettingsTab(),
                icon: Icon(Icons.settings),
                activeIcon: Icon(Icons.settings),
            ),
        };
    });

Adding Alerts to Tabs

You can add alerts to your tabs.

Sometime you might not want to show a badge count, but you want to show an alert to the user.

To add an alert to a tab, you can use the NavigationTab.alert class.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    NavigationHubLayout? layout = NavigationHubLayout.bottomNav();
    ... 
    _MyNavigationHubState() : super(() async {
        return {
            0: NavigationTab.alert(
                title: "Chats",
                page: ChatTab(),
                icon: Icon(Icons.message),
                activeIcon: Icon(Icons.message),
                alertColor: Colors.red,
                alertEnabled: true,
                rememberAlert: false,
            ),
            1: NavigationTab(
                title: "Settings",
                page: SettingsTab(),
                icon: Icon(Icons.settings),
                activeIcon: Icon(Icons.settings),
            ),
        };
    });

This will add an alert to the Chat tab with a red color.

You can also update the alert programmatically.

/// Enable the alert
BaseNavigationHub.stateActions.alertEnableTab(tab: 0);

/// Disable the alert
BaseNavigationHub.stateActions.alertDisableTab(tab: 0);

Maintaining state

By default, the state of the Navigation Hub is maintained.

This means that when you navigate to a tab, the state of the tab is preserved.

If you want to clear the state of the tab each time you navigate to it, you can set maintainState to false.

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
    @override
    bool get maintainState => false;
    ... 
}

State Actions

State actions are a way to interact with the Navigation Hub from anywhere in your app.

Here are some of the state actions you can use:

  /// Reset the tab
  /// E.g. MyNavigationHub.stateActions.resetTabState(tab: 0);
  resetTabState({required tab});

  /// Update the badge count
  /// E.g. MyNavigationHub.updateBadgeCount(tab: 0, count: 2);
  updateBadgeCount({required int tab, required int count});

  /// Increment the badge count
  /// E.g. MyNavigationHub.incrementBadgeCount(tab: 0);
  incrementBadgeCount({required int tab});

  /// Clear the badge count
  /// E.g. MyNavigationHub.clearBadgeCount(tab: 0);
  clearBadgeCount({required int tab});

To use a state action, you can do the following:

MyNavigationHub.stateActions.updateBadgeCount(tab: 0, count: 2);
// or
MyNavigationHub.stateActions.resetTabState(tab: 0);

Loading Style

Out the box, the Navigation Hub will show your default loading Widget (resources/widgets/loader_widget.dart) when the tab is loading.

You can customize the loadingStyle to update the loading style.

Here's a table for the different loading styles you can use: // normal, skeletonizer, none

Style Description
normal Default loading style
skeletonizer Skeleton loading style
none No loading style

You can change the loading style like this:

@override
LoadingStyle get loadingStyle => LoadingStyle.normal();
// or
@override
LoadingStyle get loadingStyle => LoadingStyle.skeletonizer();

If you want to update the loading Widget in one of the styles, you can pass a child to the LoadingStyle.

@override
LoadingStyle get loadingStyle => LoadingStyle.normal(
    child: Center(
        child: Text("Loading..."),
    ),
);

Now, when the tab is loading, the text "Loading..." will be displayed.

Example below:

class _MyNavigationHubState extends NavigationHub<MyNavigationHub> {
    ... 
     _BaseNavigationHubState() : super(() async {
      
      await sleep(3); // simulate loading for 3 seconds

      return {
        0: NavigationTab(
          title: "Home",
          page: HomeTab(),
          icon: Icon(Icons.home),
          activeIcon: Icon(Icons.home),
        ),
        1: NavigationTab(
          title: "Settings",
          page: SettingsTab(),
          icon: Icon(Icons.settings),
          activeIcon: Icon(Icons.settings),
        ),
      };
    });

    @override
    LoadingStyle get loadingStyle => LoadingStyle.normal(
        child: Center(
            child: Text("Loading..."),
        ),
    );
    ... 
}

Creating a Navigation Hub

To create a Navigation Hub, you can use Metro, use the below command.

metro make:navigation_hub base

This will create a base_navigation_hub.dart file in your resources/pages/ directory and add the Navigation Hub to your routes/router.dart file.