yana 0.1.0 copy "yana: ^0.1.0" to clipboard
yana: ^0.1.0 copied to clipboard

Yet Another Navigation Approach

YANA - Yet Another Navigation Approach #

YANA provides a convenient way to use declarative state-driven testable navigation. It is Navigator 2.0 without rough edges.

Declarative #

The declarative approach separates navigation from UI and business logic. No more Navigator.push and Navigator.pop in surprising places.

TreeNavNode buildNavigation(state) => firstOf<AppState>(
      when: always,
      pages: [
        _loginFlow(),
        _authedFlow(),
      ],
    )(state);

_loginFlow() => anyOf<AppState>(
      when: hasNoUser,
      pages: [
        materialPage(
          when: always,
          name: ScreenKeys.authorization,
          builder: (_) => const LoginScreen(),
          onPopPage: () => false,
        )
      ],
    );

_authedFlow() => anyOf<AppState>(
      when: hasUser,
      pages: [
        materialPage(
          when: always,
          name: ScreenKeys.books,
          builder: (_) => const BooksScreen(),
          onPopPage: () => false,
        ),
        materialPage(
          when: hasSelectedBook,
          name: ScreenKeys.bookDetails,
          builder: (_) => const BookDetailsScreen(),
          onPopPage: () => false,
        ),
      ],
    );

State-driven #

Always predictable screens based on your state. Thanks to Navigator 2.0!

class AppRouterDelegate {
  TreeNavNode _navNode;
  StreamSubscription<AppState> _storeSubscription;

  AppRouterDelegate(store) {
    _storeSubscription = store.onChange.listen((event) {
      _navNode = buildNavigation(store);
      notifyListeners();
    });
  }

  @override
  Widget build(BuildContext context) {
    final node = _navNode;
    final pages = [...node.pages];

    return Navigator(
      key: navigatorKey,
      pages: pages,
      onPopPage: (route, result) {
        if (node.onPopPage!(route, result)) {
          return route.didPop(result);
        }
        return false;
      },
    );
  }
}

Testable #

Simple unit tests guarantee that each state is translated to the expected navigation configuration. Check tests in demos for details.

var pages = buildNavigation(state).pages;

expect(pages, hasLength(1));
expect(pages[0].name, equals(ScreenKeys.authorization));

state.loggedIn = true;
pages = buildNavigation(state).pages;

expect(pages, hasLength(1));
expect(pages[0].name, equals(ScreenKeys.books));

Getting Started #

  • Add yana package to your pubspec.yaml
  • Define buildNavigation function
  • Create your AppRouterDelegate that triggers buildNavigation for required state changes
  • Done!

Check examples with redux and provider state management.

Advanced #

How to customize a presentation of a page? #

Check implementation popUpDialog for inspiration.

Status #

  • Production-ready. The library has been used in multiple applications since 2019.
  • You can expect breaking changes before the package reaches 1.0.0 based on community feedback.
4
likes
130
pub points
10%
popularity

Publisher

unverified uploader

Yet Another Navigation Approach

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, flutter_lints

More

Packages that depend on yana