riverpod_navigator 0.29.0 copy "riverpod_navigator: ^0.29.0" to clipboard
riverpod_navigator: ^0.29.0 copied to clipboard

outdated

Simple but powerfull Flutter navigation with riverpod, freezed and Navigator 2.0.

Riverpod navigation #

Simple but powerful Flutter navigation with riverpod, freezed and Navigator 2.0 that solves the following: #

  • Strictly typed navigation:
    you can use navigate([HomeSegment(),BookSegment(id: 2)]); instead of navigate('home/book;id:2'); in your code
  • asynchronous navigation
    is the case when changing the navigation state requires asynchronous actions (such as loading or saving data from the Internet)
  • multiple providers
    is the case when the navigation state depends on multiple riverpod providers
  • easier coding:
    the problem of navigation is reduced to manipulation an immutable collection
  • better separation of concerns: UI x Model (thanks to riverpod 👍):
    navigation logic can be developed and tested without typing a single flutter widget
  • nested navigation
    just use the nested riverpod ProviderScope() and Flutter Router widget

Terminology used #

Take a look at the following terms related to URL path home/book;id=2

  • string-path: final stringPath = 'home/book;id=2';
  • string-segment: the string-path consists of two slash-delimited string-segments (home and book;id=2)
  • typed-segment: (class TypedSegment {}'s descendant) describes coresponding string-segment's (HomeSegment() and BookSegment(id:2))
  • typed-path: (typedef TypedPath = List<TypedSegment>) describes coresponding string-path ([HomeSegment(), BookSegment(id:2)];)
  • Flutter Navigator 2.0 navigation-stack is uniquely determined by the TypedPath (where each TypedSegment instance corresponds to a screen and page instance):
    [MaterialPage (child: HomeScreen(HomeSegment())), MaterialPage (child: BookScreen(BookSegment(id:2)))]

Simple example #

Create an application using these simple steps:

Step1 - define classes for the typed-segment #

Note: fromUrlPars and toUrlPars helps to convert typed-segment to string-segment and back.

class HomeSegment extends TypedSegment {
  const HomeSegment();
  factory HomeSegment.fromUrlPars(UrlPars pars) => const HomeSegment();
}

class PageSegment extends TypedSegment {
  const PageSegment({required this.title});
  factory PageSegment.fromUrlPars(UrlPars pars) => PageSegment(title: map.getString('title'));
  @override
  void toUrlPars(UrlPars pars) => map.setString('title', title);

  final String title;
}

Step2 - configure AppNavigator... #

by extending the RNavigator class:

class AppNavigator extends RNavigator {
  AppNavigator(Ref ref)
      : super(
          ref,
          [
            RRoute<HomeSegment>(HomeSegment.fromUrlPars, HomeScreen.new), // build a HomeScreen for HomeSegment
            RRoute<PageSegment>(PageSegment.fromUrlPars, PageScreen.new), // build a PageScreen for PageSegment
          ],
        );
}

Step3 - use the AppNavigator in MaterialApp.router #

If you are familiar with the Flutter Navigator 2.0 and the riverpod, the following code is clear:

class App extends ConsumerWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final navigator = ref.read(navigatorProvider) as AppNavigator;
    return MaterialApp.router(
      title: 'Riverpod Navigator Example',
      routerDelegate: navigator.routerDelegate,
      routeInformationParser: navigator.routeInformationParser,
      debugShowCheckedModeBanner: false,
    );
  }
}

Step4 - place and configure riverpod ProviderScope ... #

... in main entry point

void main() => runApp(
      ProviderScope(
        // home-path and navigator constructor are required
        overrides: RNavigatorCore.providerOverrides([HomeSegment()], AppNavigator.new),
        child: const App(),
      ),
    );

And that's all #

Navigation to a specific screen is performed as follows:

// navigation to PageScreen
ElevatedButton(
  onPressed: () => ref.read(navigatorProvider).navigate([HomeSegment(), PageSegment(title: 'Page')]),

// navigation to HomeScreen
ElevatedButton(
  onPressed: () => ref.read(navigatorProvider).navigate([HomeSegment()]),

Running applications, source code and test, see:

Testing #

Before developing a GUI, it is good practice to develop and test the invisible part of the application (app model and state). It is recommended to use a dart test environment, see:

  test('navigation test', () async {
    final container = ProviderContainer(overrides: RNavigatorCore.providerOverrides([HomeSegment()], AppNavigator.new));
    final navigator = container.read(navigatorProvider);

    Future navigTest(Future action(), String expected) async {
      await action();
      await container.pump();
      expect(navigator.navigationStack2Url, expected);
    }

    await navigTest(() => navigator.navigate([HomeSegment()]), 'home');

    await navigTest(() => navigator.navigate([HomeSegment(), PageSegment(title: 'Page')]), 'home/page;title=Page');

    await navigTest(() => navigator.pop(), 'home');

    await navigTest(() => navigator.push(PageSegment(title: 'Page2')), 'home/page;title=Page2');

    await navigTest(() => navigator.replaceLast<PageSegment>((old) => PageSegment(title: 'X${old.title}')), 'home/page;title=XPage2');
  });

Other features and examples #

Installation of examples #

After cloning the riverpod_navigator repository, go to examples/doc subdirectory and execute:

  • flutter create .
  • flutter pub get

See the /lib subdirectory for examples.

riverpod_navigator

As you can see, changing the Input state starts the async calculation. The result of the calculations is Output state which can have app-specific Side effects. Navigator 2.0 RouterDelegate is then synchronized with navigationStackProvider

Roadmap #

I prepared this package for my new project. Its further development depends on whether the community will use it.

  • proofreading because my English is not good. Community help is warmly welcomed.
  • parameterization allowing Cupertino
25
likes
0
pub points
60%
popularity

Publisher

unverified uploader

Simple but powerfull Flutter navigation with riverpod, freezed and Navigator 2.0.

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

flutter, flutter_riverpod, meta, riverpod_navigator_core

More

Packages that depend on riverpod_navigator