GithubHelp home page GithubHelp logo

nubank / nuvigator Goto Github PK

View Code? Open in Web Editor NEW
265.0 703.0 32.0 1.01 MB

A powerful routing abstraction over Flutter Navigator, with nested Navigator and Deeplinks

License: Apache License 2.0

Swift 0.42% Objective-C 0.04% Dart 98.16% Go 1.38%

nuvigator's Introduction

Nuvigator

CircleCI Pub

Routing and Navigation package.

Não fala bem inglês? Leia o README_PT

What

Nuvigator provides a powerful routing abstraction over Flutter's own Navigators. Model complex navigation flows using a mostly declarative and concise approach, without needing to worry about several tricky behaviors that Nuvigator handles for you.

Nuvigator can help you with:

  • Large/Modular Apps: Where you need to have an unified API to able to register routes and design relationship between them
  • Nested Navigation: When you want to have nested/children Navigator inside your app, creating the concept of self contained flows
    • Handles Navigation thought Nuvigator ins your Widget Tree, not need to know where your route is declared
    • Handles pop behavior when a nested Navigator reaches it's end, is able to transparently forward pop results into underlying caller, provider helpers to deal with nested navigation
    • Handles Hero animation/transition between nested Navigators
    • Handles Android back button correctly on nested Navigators
    • Improve support for nested PageRoutes with NuvigatorPageRoute mixin
  • Using DeepLinks: You want to navigate inside your App using DeepLinks, with support for Path Parameters and Query Parameters
  • A declarative, easy to use API to declare and compose Routes together

API Documentation

Focus on providing a more flexible, easier and dynamic API for declaring Navigation and Routing

Quick Start

The simplest you can get:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Nuvigator App',
      builder: Nuvigator.routes(
        initialRoute: 'home',
        screenType: materialScreenType,
        routes: [
          NuRouteBuilder(path: 'home', builder: (_, __, ___) => HomeScreen()),
          NuRouteBuilder(path: 'second', builder: (_, __, ___) => SecondScreen()),
        ],
      ),
    );
  }
}

A more complete example:

import 'package:nuvigator/next.dart'; // import the next file instead of `nuvigator.dart`
import 'package:flutter/material.dart';

// Define a new NuRoute
class MyRoute extends NuRoute {
  @override
  String get path => 'my-route';

  @override
  ScreenType get screenType => materialScreenType;

  @override
  Widget build(BuildContext context, NuRouteSettings settings) {
    return MyScreen(
      onClick: () => nuvigator.open('next-route'),
    );
  }
}

// Define your NuRouter
class MyRouter extends NuRouter {
  @override
  String get initialRoute => 'my-route';

  @override
  List<NuRoute> get registerRoutes => [
    MyRoute(),
  ];
}

// Render
Widget build(BuildContext context) {
  return Nuvigator(
    router: MyRouter(),
  );
}

License

Apache License 2.0

nuvigator's People

Contributors

alifyz avatar cisneiros avatar comigor avatar daniel-maranhao avatar felipefpx avatar julienmalige avatar leoiacovini avatar leomhl avatar lubritto avatar marcobiscaro2112 avatar mateusvtt avatar miguelslemos avatar nidib avatar obraca avatar raapperez avatar rafaelring avatar raqg avatar realshovanshah avatar renatoaugustofranca avatar souzavitor avatar stwonary avatar tuannyharumi avatar wladmirjunior avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nuvigator's Issues

Error occurred when pass argument to ScreenRoute method

When I run flutter pub run build_runner watch --delete-conflicting-outputs
generate file not created and show some error outputs

line 1, column 924: Expected to find '}'.

1 │ Future toMerchantScreen() { return nuvigator.pushNamed(MerchantRoutes.merchantScreen,); } Future pushReplacementToMerchantScreen({TO result}) { return nuvigator.pushReplacementNamed<Object, TO>(MerchantRoutes.merchantScreen, result: result,); } Future pushAndRemoveUntilToMerchantScreen({@required RoutePredicate predicate}) { return nuvigator.pushNamedAndRemoveUntil(MerchantRoutes.merchantScreen, predicate,); } Future popAndPushToMerchantScreen({TO result}) { return nuvigator.popAndPushNamed<Object, TO>(MerchantRoutes.merchantScreen, result: result,); } Future toMerchantPhotosScreen({List<AssetImageModel*>* photos}) { return nuvigator.pushNamed(MerchantRoutes.merchantPhotosScreen, arguments: {'photos': photos,},); } Future pushReplacementToMerchantPhotosScreen({List<AssetImageModel*>* photos, TO result}) { return nuvigator.pushReplacementNamed<Object, TO>(MerchantRoutes.merchantPhotosScreen, arguments: {'photos': photos,}, result: result,); } Future pushAndRemoveUntilToMerchantPhotosScreen({List<AssetImageModel*>* photos, @required RoutePredicate predicate}) { return nuvigator.pushNamedAndRemoveUntil(MerchantRoutes.merchantPhotosScreen, predicate, arguments: {'photos': photos,},); } Future popAndPushToMerchantPhotosScreen({List<AssetImageModel*>* photos, TO result}) { return nuvigator.popAndPushNamed<Object, TO>(MerchantRoutes.merchantPhotosScreen, arguments: {'photos': photos,}, result: result,); }

@NuRoute()
ScreenRoute merchantPhotosScreen({
  List<AssetImageModel> photos,
}) => ScreenRoute(
  builder: (BuildContext context) => MerchantPhotosScreen(
    photos: photos,
  ),
);

Implementing a custom tab navigator

With the new documentation branch, is it possible to implement a tab navigator? In theory, it should be one screen with a fixed state which keeps track of the bottom tabs, and navigating within it only changes the top screen (child widget).

In my attempt here, it works visually but a new tab bar widget instance is created every time I navigate within the router, which causes the tab bar state not to persist.
Because of this, the animated offset value for the current active route doesn't work, because the entire screen is replaced (including the bottom tabbar widget) on each navigation including the bottom tab navigator so the offset is always the initial value.

Router

@NuRouter()
class HomeScreenTabsRouter extends BaseRouter {
  
  
  @NuRoute()
  ScreenRoute myWalletScreen() => ScreenRoute(
        builder: (_) => MyWalletScreen(),
      );

  @NuRoute()
  ScreenRoute transactionsScreen() => ScreenRoute(
        builder: (_) => TransactionsScreen(),
      );

  @NuRoute()
  ScreenRoute contactsScreen() => ScreenRoute(
        builder: (_) => ContactsScreen(),
      );

  @NuRoute()
  ScreenRoute notificationsScreen() => ScreenRoute(
        builder: (_) => NotificationsScreen(),
      );

  @NuRoute()
  ScreenRoute profileScreen() => ScreenRoute(
        builder: (_) => ProfileScreen(),
      );

  @override
  WrapperFn get screensWrapper =>
      (BuildContext context, Widget child) => TabBar(child: child);

  @override
  Map<RouteDef, ScreenRouteBuilder> get screensMap =>
      _$homeScreenTabsScreensMap(this);
}

TabBar widget

The tab bar widget is just a column which renders the child screen at the top (passed in by the router wrapper above), and shows the tab bar buttons at the footer which are colored based on the active route.

class TabBar extends StatefulWidget {
  final Widget child;
  TabBar({@required this.child});

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

class _TabBarState extends State<TabBar> with SingleTickerProviderStateMixin {
  AnimationController navBarOffsetController;
  Animation<double> navBarOffsetAnimation;
  Tween<double> navBarOffsetTween = Tween<double>(
      begin: 0 * (ScreenUtil.screenWidthDp / 5) +
          (ScreenUtil.screenWidthDp / 5) * 0.3,
      end: 0 * (ScreenUtil.screenWidthDp / 5) +
          (ScreenUtil.screenWidthDp / 5) * 0.3);

  @override
  initState() {
    super.initState();
    navBarOffsetController =
        AnimationController(duration: Duration(milliseconds: 500), vsync: this);

    navBarOffsetAnimation = navBarOffsetTween.animate(
        CurvedAnimation(parent: navBarOffsetController, curve: Curves.ease))
      ..addListener(() => setState(() {
            print('New val: ${navBarOffsetAnimation.value}');
          }));
  }

  @override
  dispose() {
    navBarOffsetController.dispose();
    super.dispose();
  }

  moveNavBarIndicator(int pos) {
    navBarOffsetTween.begin = navBarOffsetTween.end;
    navBarOffsetTween.end = pos * (ScreenUtil.screenWidthDp / 5) +
        (ScreenUtil.screenWidthDp / 5) * 0.3;
    navBarOffsetController.reset();
    navBarOffsetController.forward();
  }

  @override
  Widget build(BuildContext context) {
    final stores = Provider.of<RootStore>(context);
    return Observer(
        builder: (_) => BottleScreen(
              children: <Widget>[
                Expanded(child: Container(child: widget.child)),
                Stack(children: [
                  Positioned(
                      left: navBarOffsetAnimation.value,
                      child: _NavIndicator()),
                  Container(
                      decoration: BoxDecoration(
                          border: Border(
                              top: BorderSide(
                                  width: 1, color: Color(0x1C7C7FA6)))),
                      child: Row(
                          // mainAxisAlignment: MainAxisAlignment.spaceAround,
                          children: <Widget>[
                            _NavItem(
                                iconPath: 'assets/images/money-wallet.svg',
                                navPath: HomeScreenTabsRoutes.myWalletScreen,
                                onTap: () {
                                  Nuvigator.of(context).pushNamedAndRemoveUntil(
                                      HomeScreenTabsRoutes.myWalletScreen,
                                      (_) => false);
                                  moveNavBarIndicator(0);
                                }),
                            _NavItem(
                                iconPath: 'assets/images/coins-stack.svg',
                                navPath:
                                    HomeScreenTabsRoutes.transactionsScreen,
                                onTap: () {
                                  Nuvigator.of(context).pushNamedAndRemoveUntil(
                                      HomeScreenTabsRoutes.transactionsScreen,
                                      (route) =>
                                          route.settings.name ==
                                          HomeScreenTabsRoutes.myWalletScreen);
                                  moveNavBarIndicator(1);
                                }),
                            _NavItem(
                                iconPath: 'assets/images/contacts.svg',
                                navPath: HomeScreenTabsRoutes.contactsScreen,
                                onTap: () {
                                  Nuvigator.of(context).pushNamedAndRemoveUntil(
                                      HomeScreenTabsRoutes.contactsScreen,
                                      (route) =>
                                          route.settings.name ==
                                          HomeScreenTabsRoutes.myWalletScreen);
                                  moveNavBarIndicator(2);
                                }),
                            _NavItem(
                                iconPath: 'assets/images/notifications.svg',
                                navPath:
                                    HomeScreenTabsRoutes.notificationsScreen,
                                onTap: () {
                                  Nuvigator.of(context).pushNamedAndRemoveUntil(
                                      HomeScreenTabsRoutes.notificationsScreen,
                                      (route) =>
                                          route.settings.name ==
                                          HomeScreenTabsRoutes.myWalletScreen);
                                  moveNavBarIndicator(3);
                                }),
                            _NavItem(
                                iconPath: stores.profileStore
                                    .currentSelectedProfileObj.avatar,
                                navPath: HomeScreenTabsRoutes.profileScreen,
                                onTap: () {
                                  Nuvigator.of(context).pushNamedAndRemoveUntil(
                                      HomeScreenTabsRoutes.profileScreen,
                                      (route) =>
                                          route.settings.name ==
                                          HomeScreenTabsRoutes.myWalletScreen);
                                  moveNavBarIndicator(4);
                                }),
                          ]))
                ]),
              ],
            ));
  }
}

Separate builder and runtime into two different packages

We should follow the community convention in splitting packages that contain code generation into different sub-packages. One containing the annotation (and in this case, maybe the Runtime code), and another one just with builder/generator code.

Documentation update and new instructions

I'm trying to follow the documentation in order to make an example project with Nuvigator and I've found two problems with that:

  • The documentation examples suggests that we use a GlobalRouter instance as the top level Router but looks like this class was removed in version 0.3.0.
  • Since the generated code is using Extensions, I had to do some research to find out that I'd needed to create a new file in the root directory with the name analysis_options.yaml and the following content to make it to work:
enable-experiment:
  - extension-methods

What about updating the docs with those details?

Error trying to run the Nuvigator example

I'm trying to assess Nuvigator before using in one of my projects but after struggling to make it work in a more complex codebase, I've created the simplest possible project and I'm receiving the following error when I try to run it in the iOS Simulator:

Launching lib/main.dart on iPhone Xs Max in debug mode...

Compiler message:
../../sdks/flutter/.pub-cache/hosted/pub.dartlang.org/nuvigator-0.3.0/lib/src/nuvigator.dart:276:24: Error: This expression has type 'void' and can't be used.
      isPopped = super.pop<T>(result);
                       ^
Target kernel_snapshot failed: Exception: Errors during snapshot creation: null
Failed to build bundle.
Error launching application on iPhone Xs Max.

Could anyone help me with that?
Example project repository: https://github.com/shrpereira/nuvigator_flutter_app

Dynamic module navigation

Hey Nuvigator team,

I'm trying to extend the lib, but my limited knowledge about Flutter / Dart is blocking me.

I have a "base" application, where I gonna have only configuration setup and two screens (settings and about).
All the other features are distributed in different packages (or modules), for example FeedModule, ScheduleModule, FormModule, etc.

Based on a build script, I gonna change pubspec.yaml to add as dependency only the modules I need for that build. So, I can generate different apps with different modules arrangements.

For each module, I created the its own Router with all navigation logic for that module. But I can't do the Router for the main application because I don't know beforehand which module is included.

Is it possible somehow to have the Router implementation creating code for the routes after processing the packaged included in the build?

Thanks
Neto

Add popUntil{routeName} generated method

Hi,

Nuvigator has some generated methods that helps a lot, I would like to add a new one popUntil{routeName}. It will call the popUntil with the predicate checking the name of the route.

I can try to implement this, if you think that this feature will be nice.

Implementing a custom tab navigation - 'Router operation requested with a context that does not include a Router of the provided type.'

I'm trying to implement my own tab navigation (not using MaterialApp or CupertinoApp), using Nuvigator.

Here is my attempt so far:

├── _router
│   ├── index.dart // The router definition
│   ├── index.g.dart
│   └── tab_bar.dart // My tab bar component which takes a child to render within it
├── my_wallet
│   └── index.dart // Child route #1
└── transactions
    └── index.dart // Child route #2

routes/authenticated_tabs/home_screen_tabs/_router/index.dart:

@NuRouter()
class HomeScreenTabsRouter extends Router {
  @NuRoute()
  ScreenRoute myWalletScreen() => ScreenRoute(
        builder: (_) => TabBar(child: MyWalletScreen(), activeIndex: 0),
      );

  @NuRoute()
  ScreenRoute transactionsScreen() => ScreenRoute(
        builder: (context) =>
            TabBar(child: TransactionsScreen(), activeIndex: 1),
      );

  @override
  Map<RouteDef, ScreenRouteBuilder> get screensMap => _$screensMap;
}

routes/authenticated_tabs/home_screen_tabs/_router/tab_bar.dart

class TabBar extends StatefulWidget {
  final Widget child;
  final int activeIndex;
  TabBar({@required this.child, @required this.activeIndex});

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

class _TabBarState extends State<TabBar> {
  @override
  Widget build(BuildContext context) {
    return BottleScreen(
      children: <Widget>[
        Expanded(child: Container(child: widget.child)),
        Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              TouchableHighlight(
                  child: BottleTextBold('Wallet',
                      style: TextStyle(
                          color: widget.activeIndex == 0
                              ? BottleColors.purple
                              : BottleColors.asphaltGrey)),
                  onTap: () {
                    Router.of<HomeScreenTabsRouter>(context).toMyWalletScreen();
                    // Nuvigator.of(context).pushReplacementNamed(
                    //     HomeScreenTabsRoutes.myWalletScreen);
                  }),
              TouchableHighlight(
                  child: BottleTextBold('Transactions',
                      style: TextStyle(
                          color: widget.activeIndex == 1
                              ? BottleColors.purple
                              : BottleColors.asphaltGrey)),
                  onTap: () {
                    Router.of<HomeScreenTabsRouter>(context)
                        .toTransactionsScreen();
                    // Nuvigator.of(context).pushReplacementNamed(
                    //     HomeScreenTabsRoutes.myWalletScreen);
                  }),
            ])
      ],
    );
  }
}

routes/authenticated_tabs/home_screen_tabs/my_wallet/index.dart

class MyWalletScreen extends StatefulWidget {
  @override
  _MyWalletScreen createState() => _MyWalletScreen();
}

class _MyWalletScreen extends State<MyWalletScreen> {
  @override
  void initState() {
    super.initState();
    final stores = Provider.of<RootStore>(context, listen: false);
  }

  @override
  Widget build(BuildContext context) {
    final stores = Provider.of<RootStore>(context);
    return H1('Home screen placeholder');
  }
}

routes/authenticated_tabs/home_screen_tabs/transactions/index.dart

class TransactionsScreen extends StatefulWidget {
  @override
  _TransactionsScreen createState() => _TransactionsScreen();
}

class _TransactionsScreen extends State<TransactionsScreen> {
  @override
  void initState() {
    super.initState();
    final stores = Provider.of<RootStore>(context, listen: false);
  }

  @override
  Widget build(BuildContext context) {
    final stores = Provider.of<RootStore>(context);
    return H1('Transactions screen placeholder');
  }
}

Result: I can load to the my_wallet screen and we see it there, along with my 2 tab navigator buttons at the bottom:
Screen Shot 2020-02-11 at 10 40 43 AM

But, when I try to navigate within this router to the other screen, it's saying there's no Nuvigator within the current context:

Router operation requested with a context that does not include a Router of the provided type.

You can see in my code above I also tried navigating via Nuvigator.of(context).. but that just returned a null error since there's no Nuvigator within my context.

Is this an error in the way I've implemented my tab navigator?

Nuvigator is not working with Flutter Navigator 2.0 API

Flutter is being updated with a new Navigator API and some of the changes that are being done are breaking Nuvigator, one issue is described here: #23

We need to dig down into those new changes and make Nuvigator compatible with them, and afterwards build/improve the API based on the new features provided by the 2,0 API.

How to call Nuvigator from outside of build context?

With built-in navigator I used GetIt() and a global key to do this, how can I access Nuvigator to navigate screens outside of a build function?

Here's an example:

Run this just before runApp()

void setupLocator() {
  GetIt.instance
      .registerLazySingleton<NavigationService>(() => NavigationService());
}

NavigationService definition:

class NavigationService {
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
  final GlobalKey<NavigatorState> navigatorKeyAuth =
      GlobalKey<NavigatorState>();

  /// Navigate to a named route with optional [arguments].
  Future<dynamic> pushNamed(String routeName, {Object arguments}) {
    return navigatorKey.currentState.pushNamed(routeName, arguments: arguments);
  }

  /// Navigate to a named route but reset the stack so the user can't go back, with optional [arguments].
  Future<dynamic> pushNamedReset(String routeName,
      {Object arguments, String popUntil}) {
    return navigatorKey.currentState.pushNamedAndRemoveUntil(
        routeName, (route) => route.settings.name == popUntil ?? '/',
        arguments: arguments);
  }
}

Then I can navigate from anywhere using this:

GetIt.instance<NavigationService>().pushNamedReset('/screen_name');

Flutter Dev channel compatibility

Hello,

To make some tests with Flutter Desktop I changed to Flutter Dev Channel, and in this version has a new Flutter class called Router that conflicts with Router of Nuvigator.
I think that this versão will merge to Flutter release soon, you know this changes?

Maybe be better prepared for these changes.

When to use @NuRouter or when to use @NuRoute which returns a Nuvigator?

When is it appropriate to use this format:

@NuRouter()
class AuthenticatedRouter extends Router {

  @NuRoute()
  ScreenRoute<String> homeScreenTabsRoutes() => ScreenRoute(
        builder: Nuvigator(
          router: HomeScreenTabsRouter(),
          initialRoute: HomeScreenTabsRoutes.myWalletScreen,
          screenType: fadeInOutScreenType,
        ),
      );

  @override
  Map<RouteDef, ScreenRouteBuilder> get screensMap => _$screensMap;
}

vs this?

@NuRouter()
class AuthenticatedRouter extends Router {

  @NuRouter()
  final HomeScreenTabsRouter homeScreenTabsRouter = HomeScreenTabsRouter();

  @override
  Map<RouteDef, ScreenRouteBuilder> get screensMap => _$screensMap;
}

Guinea Pig: First time using Nuvigator feedback

Hey all!

I've been asked by Vini to check out the Nuvigator package and try to use it to provide feedback. I've recorded some notes as I attempted to implement Nuvigator for my first time so I could hopefully provide some constructive feedback!

Also note: It might be easier to chat in person about this stuff than go through a long email chain, haha :) Hit me up and happy to find a time to video chat / discuss!

Method

  • Read documentation in README
  • Clone repo
  • Run sample and play with the app
  • Look at sample code to understand how pieces fit together
  • Try it for myself!

First impressions

Note: These first impressions don't mean my opinion is right, but I want to give honest feedback as someone who's familiar with the default Navigator and is looking at this for the first time.

  • Code generation for Route params seems nice!
  • Support out of the box for deeplinks -- yay!
  • README says it works like navigator, "but with several custom improvements and features." It would be helpful if those improvements were explicitly stated right after that line! There's some mention of Deeplinks and nested navigation, but you can handle those scenarios with the default Navigator, so it'd be great to maybe even hear the pain points this library aims to solve.
  • Nuvigator is a child of MaterialApp which already has a Navigator -- are both needed? Should there be a NuvigatorApp which is like WidgetsApp or MaterialApp?
  • Documentation doesn't have a great "Getting Started" section that you can copy/pasta, need to sort of extract code from the Sample and know how builders work in general
  • When something goes wrong, it's a bit hard to tell why. I got lost when I got the following error a few times: "package:flutter/src/widgets/framework.dart': Failed assertion: line 5438 pos 12: 'child == _child': is not true." This did not include a stacktrace back to any code I had written or was generated. I just played with my code until it generated something different that worked, but I didn't feel confident I'd fixed the issue or really know what the issue was. It feels a bit like you have to understand how this package generates code to understand how to write code to make it happy.
  • Just a gut feeling, but it feels like parts of this package kinda work against the framework a bit. Back buttons in AppBars do not work reliably or show the wrong icon, Android back button works differently than Back buttons in App Bars, no use of Route objects to control the animation from one screen to another (kind of buried in the ScreenRoute class), passing a parent BuildContext into a Widget as a constructor property, extending from classes like ScreenOneScreen to get data rather than using Widget composition or passing data into the Widget via constructor properties.
  • So many different Navigators to work with! Nuvigator.of(context), nuvigator passed into Screen widgets (these two might be different than one another depending on the context -- have to look into it more), SampleOneNavigation, SampleOneNavivation.of(context).nestedNavigator, etc. I kinda miss the beauty of a Widget being completely dumb and just saying "Navigator closest to me in the context, do your job!" rather than having to know exactly which Navigator I'm looking for.

Again, these were just my initial impressions. Things like "So many navigators" could easily be seen as "well, the person giving this feedback just doesn't understand the use case and the complexity we're trying to deal with" -- which is true! All I'd say: After using this library for 3-4 hours, I'd probably just write this stuff by hand. Until I got really good with this library, I think it'd actually be a bit less confusing for me.

Sample

  • Clicking "Go to sample one with Flutter navigation" takes you to "Sample One / Screen One." There's a back button in the AppBar that does not work, but the Android "back" button does indeed work. I'm not sure what the intended effect is here, but did make me a bit "worried" about using this library if those two behaviors are different from one another since it was one of the very first things I tried and it felt like a Navigator library should nail that.
  • Same problem happens if you Navigate from Sample Two -> Sample One
  • It might be good to label the screens a bit differently, such as "1A", "1B", "2A", "2B." Kinda easy to get lost in "Sample Two Screen One" after coming from "Sample One Screen One".

Code

  • Most packages that have builders are split into two parts: The Annotations and The Builder. Annotations are included in dependencies, the builder is included in the dev_dependencies section. Example packages from the dart team: json_annotations and json_serializable, built_value and built_value_generator, etc. It might be a good idea to consider a similar split for this library?

Documentation Improvements

  • Provide Getting Started section with pubspec.yaml and my_router.dart sample file to get started.
  • Provide a couple of Recipes
    • Regular Navigation scenario
    • Nested Navigation scenario
    • Deeplink scenario
  • FAQ about errors like the ones I got above -- even better, more robust checking in the builder for missing bits. built_value is really good at this -- if you forget a part, they let you know exactly what you forgot.

[example app] problem navigating to the TextComposerScreen

Navigating using the "Compose a message" in the home screen throws the following error:

[VERBOSE-2:ui_dart_state.cc(198)] Unhandled Exception: Null check operator used on a null value
#0      DeepLinkParser.getPathParams
package:nuvigator/src/deeplink.dart:60
#1      DeepLinkParser.toNuRouteSettings
package:nuvigator/src/deeplink.dart:83
#2      NuRoute._screenRoute
package:nuvigator/src/nu_router.dart:63
#3      NuRoute._tryGetScreenRoute
package:nuvigator/src/nu_router.dart:79
#4      NuRouter._getScreenRoute
package:nuvigator/src/nu_router.dart:275
#5      NuRouter.getRoute
package:nuvigator/src/nu_router.dart:301
#6      NuvigatorState.open
package:nuvigator/src/nuvigator.dart:442
#7      HomeScreen.build.<anonymous closure>
package:example/…/screens/home_screen.dart:47
#8      HomeScreen.build.<anonymous closure>
package:example/…/screens/home_screen.dart:44
#9      _InkResponseState._handleTap
package:flutter/…/material/ink_well.dart:1005
#10     GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognize<…>

I think it's happening after the migration to null safety.

Dart 3 incompatible

Hi, folks!
It would be better to make it compatible with the Dart 3 settings screen.
How can I help with this task?
Screenshot 2023-06-14 at 20 34 27

Generated .g.dart file doesn't import flutter/widgets

So, I've created a simple Router (with no NuRoutes for now) and, when the .g.dart file was generated, a build error occured ("Undefined class 'BuildContext'").

Doing some research, it seems we can't have imports on "part of" files, but that wasn't clear.
Maybe we could add a import 'package:flutter/widgets.dart'; import requirement on README?

I'll open a PR.

For reference:

navigation.dart import 'package:nuvigator/nuvigator.dart';

part 'navigation.g.dart';

@NuRouter()
class TestRouter extends BaseRouter {
@override
String get deepLinkPrefix => 'test/';

@override
Map<RouteDef, ScreenRouteBuilder> get screensMap =>
_$testScreensMap(this);
}

navigation.g.dart // GENERATED CODE - DO NOT MODIFY BY HAND

part of 'navigation.dart';

// **************************************************************************
// NuvigatorGenerator
// **************************************************************************

class TestRoutes {}

class TestNavigation {
TestNavigation(this.nuvigator);

final NuvigatorState nuvigator;

static TestNavigation of(BuildContext context) =>
TestNavigation(Nuvigator.of(context));
}

Map<RouteDef, ScreenRouteBuilder> _$testScreensMap(
SplitTransactionRouter router) {
return {};
}

Flutter Web

Does this support Flutter web as well as mobile ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.