Coder Social home page Coder Social logo

schabanbo / qlevar_router Goto Github PK

View Code? Open in Web Editor NEW
86.0 86.0 22.0 13.66 MB

Manage you project Routes. Create nested routes. Simply navigation without context to your pages. Change only one sub widget in your page when navigating to new route.

License: MIT License

Dart 91.48% HTML 0.46% CMake 2.55% C++ 5.25% C 0.23% Shell 0.02%
dart flutter nasted-navigation navigation navigation2 router

qlevar_router's People

Contributors

basmilius avatar devhammed avatar jessicamrbr avatar ming-chu avatar obadajasm avatar q876625596 avatar rockingdice avatar rounce avatar schabanbo avatar sociosarbis avatar tanmoy27112000 avatar tejhackerdev 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

Watchers

 avatar  avatar

qlevar_router's Issues

Thank you for this Qlever Router

Thank You so much πŸ₯³πŸŽ‰πŸš€.

This package is a life safe saver.... you have no idea the sleepless nights I have had simply because I wanted to use Nav.2.0

replaceLast removes all routes

Hi @SchabanBo ,

I am facing an issue with replaceLast method. It seems to work like replaceAll.
I think this condition check results in this issue.

if (await _pagesController.removeAll() != PopResult.Poped)

Could you check this?

Thank you.

Pushed params always String

Any params, that pushed with route via QR.navigator.pushNamed has type String and method valueAs<T>() did not cast it to initial type.

Basic Question

Sorry if this is a basic question, but how do you navigate to a page/widget that takes a set of parameters (not URL params, but constructor params)? For example, we have a page/widget that has a constructor like:

class MyNextScreen extends StatefulWidget {
final Person employee;

const MyNextScreen (
{Key key, @required this.employee})
: super(key: key);
@OverRide
_MyNextScreen State createState() => _MyNextScreen State();
}

How do I navigate to MyNextScreen(employee: newEmployee) ?

All the examples show navigation happening to screens w/o parameters. I recognize I can pass Strings or ints via web-based parameters (e.g. https://myscreen?param1=) but how do you pass objects around while navigating?

Or am I thinking about this all wrong?
Thanks,
Bob

1.4.4 breaks web application

I am struggling to figure out what might cause a breaking change in 1.4.4 for my project when running as a website. 1.4.3 (and previous versions) all run fine. Moving to 1.4.4, the web app launches, I see my initial route but the moment I call QR.navigator.replaceAll('/login'); it crashes with the following stack trace:

Stack Trace:
STACK TRACE C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49 throw_ C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/js_array.dart 337:5 last] packages/qlevar_router/src/controllers/pages_controller.dart 30:26 removeLast packages/qlevar_router/src/controllers/pages_controller.dart 61:7 removeAll packages/qlevar_router/src/controllers/qrouter_controller.dart 167:22 replaceAll C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:5 _async packages/qlevar_router/src/controllers/qrouter_controller.dart 165:26 replaceAll packages/kiosk/bloc/application/application_cubit.dart 82:20 initializeApp C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 45:50 <fn> C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1362:47 _rootRunUnary C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1265:19 runUnary C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 155:18 handleValue C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 707:44 handleValueCallback C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 736:13 _propagateToListeners C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 542:5 [_completeWithValue] C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 580:7 <fn> C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1354:13 _rootRun C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1258:19 run C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1162:7 runGuarded C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1202:23 callback C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 40:11 _microtaskLoop C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 49:5 _startMicrotaskLoop C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 166:15 <fn>

Drawer example

Does anyone have an example of Drawer navigation working properly? If I have two pages w/an AppBar/AppDrawer, my initial navigation works correctly, but when I navigate to the first page (using QR.to('/subpage'); ) the URL in the browser bar reflects the proper URL, but the body of the Scaffold does not change. If I click the link a second time, then the screens change.

My routes look like this:

  List<QRoute> routes() => [
     QRoute(name: 'Splash', path: '/', builder: () => Launcher()),
    QRoute.withChild(name: 'Home', path: '/home', 
      builderChild: (c) => HomePage(c),
      initRoute: '/dashboard',
      children: [
        QRoute(name: 'Home Dashboard', path: '/dashboard', builder: () => HomeDashboard()),
      ]
    ),  
    QRoute.withChild(name: 'Sub Page', path: '/subpage', 
      builderChild: (c) => SubHomePage(c),
      initRoute: '/subdashboard',
      children: [
        QRoute(name: 'Sub Dashboard', path: '/subdashboard', builder: () => SubDashboard()),
      ]
    ),     
  ];

The Drawer tiles are pretty straightforward:

                ListTile(
                  leading: Icon(Icons.school),
                  title: Text("Home"),
                  onTap: () {
                    QR.to('/home');
                  },
                ),
                ListTile(
                  leading: Icon(Icons.announcement),
                  title: Text("SubPage"),
                  onTap: () {
                    QR.to('/subpage');
                  },
                ),

For completeness, here are the widgets.

void main() {
  QR.setUrlStrategy();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final routes = AppRoutes();
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'Flutter Demo',
                routeInformationParser: QRouteInformationParser(),
          routerDelegate: QRouterDelegate(routes.routes()),
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),

    );
  }
}

class Launcher extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: 
      Container(
        width: 100,
        height: 100,
        child:ElevatedButton(child: Text("launch"), onPressed: () => QR.to('/home'),)
    ));
  }
}

class HomePage extends StatelessWidget {
  final QRouter router;
  HomePage(this.router);
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      drawer: AppDrawer(),
      body: router
    );
  }
}

class HomeDashboard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("Home Dashboard")
    );
  }
}

class SubHomePage extends StatelessWidget {
  final QRouter router;
  SubHomePage(this.router);
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      drawer: AppDrawer(),
      body: router
    );
  }
}

class SubDashboard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(color: Colors.amberAccent,
      child: Text("Sub Dashboard")
    );
  }
}

bugs on `MatchController` involved wtih query and `QR.back` behavior when navigator is different

I found two bugs in following two cases:

  1. navigate to nested route with query has some common path segments as its ancestor
   testWidgets('Path query should only append to the last match',
       (tester) async {
     QR.reset();
     await tester.pumpWidget(AppWarpper(
       [
         QRoute(path: '/', builder: () => Container()),
         QRoute(path: '/zero', builder: () => Scaffold(body: Container())),
         QRoute.withChild(
             path: '/this/extra',
             builderChild: (child) => Scaffold(body: child),
             children: [
               QRoute(path: '/', builder: () => Scaffold()),
               QRoute(
                   path: '/slash/extra',
                   builder: () => Scaffold(body: WidgetThree())),
             ]),
       ],
       initPath: '/this/extra/slash/extra?id=200',
     ));
     await tester.pumpAndSettle();
     expectedPath('/this/extra/slash/extra?id=200');
     expect(QR.history.entries[0].path, '/this/extra');
   });
test('Stack with Nested Route With QR.back()', () async {
      QR.reset();
      final _ = QRouterDelegate(routes);
      await _.setInitialRoutePath('/');
      await QR.to('/nested');
      expectedPath('/nested/child');
      expectedHistoryLength(3);

      await QR.to('/nested/child-1');
      expectedPath('/nested/child-1');
      expectedHistoryLength(4);

      await QR.to('/nested/child-3');
      expectedPath('/nested/child-3');
      expectedHistoryLength(5);

      await QR.back();
      expectedPath('/nested/child-1');
      expectedHistoryLength(4);

      await QR.back();
      expectedPath('/nested/child');
      expectedHistoryLength(3);

      // navigate to route belongs to a different navigator
      await QR.to('/two');
      expectedPath('/two');
      expectedHistoryLength(4);
      
      // bug occurrs
      await QR.back();
      expectedPath('/nested/child');
      expectedHistoryLength(3);

      await QR.back();
      expectedPath('/');
      expectedHistoryLength(1);
      _.dispose();
    });

I would make a PR to fix this issue and also several typos.

It would be great to rename QRouterController.popUnit* methods to QRouterController.popUntil* , as I had no idea what the
unit means at first. But those are public methods, we have to choose a migration strategy for our users e.g. deprecation warning before renaming.πŸ˜„

Thank you for creating this well-designed library. ❀

How to make the structure of a dashboard (web) with qlevar_router?

Hello,

In the examples that you include, I have not seen the typical dashboard, an initial screen to login and when logging in, a base screen that is used to show the rest of the pages in its central zone, that is, the base screen contains a drawer located on the left, a title in the upper central area, and a central area in which the pages you are browsing are shown:
141629954-d68697a8-3e10-4b70-86a1-cfd6a1d05347

141630053-31b911af-88a8-4a63-97d0-85ca987d90f4

In fluro the code to do this is the following:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Intl.defaultLocale = 'es_ES';
    //timeago.setLocaleMessages('es', timeago.FrMessages());
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('en', 'US'), // English
        Locale('es', 'ES'), // EspaΓ±ol
      ],
      title: 'Admin Dashboard',
      initialRoute: '/',
      onGenerateRoute: Flurorouter.router.generator,
      navigatorKey: NavigationService.navigatorKey,
      scaffoldMessengerKey: NotificationsService.messengerKey,
      builder: (_, child) {
        //print('token: ');
        //print(LocalStorage.prefs.getString('token'));
        final authProvider = Provider.of<AuthProvider>(context);

        if (authProvider.authStatus == AuthStatus.checking) {
          return const SplashLayout();
        }

        if (authProvider.authStatus == AuthStatus.authenticated) {
          return DashboardLayout(child: child!);
        } else {
          return AuthLayout(child: child!);
        }

        //return AuthLayout(child: child!);
        //return DashboardLayout(child: child!);
      },
      theme: ThemeData.light().copyWith(
        scrollbarTheme: const ScrollbarThemeData().copyWith(
          thumbColor: MaterialStateProperty.all(
            Colors.grey.withOpacity(0.5),
          ),
        ),
      ),
    );
  }
}

How can I do the same with qlevar_router?

Thanks so much for the help.

Regards,
Jose

how to use function callback?

how do I make a function callback?
when I make changes in second pages and return the callback variable after back to the start page

Navigator.pushReplacement, Navigator.popUntilAndPush

First of all, really really thanks for this AMAZING package and it really save my life due to the context-less navigation for navigation 2.0. Would like to ask , is there any way to achieve effect like Navigator.pushReplacement, Navigator.popUntilAndPush, and Navigator.popUntil with current exists function?

Need Page to be recreated every time we route to it

I have a scenario where i need the page to be recreated to every time i navigate to that page.

The scenario is like this:
Let's say I have a page A which calls an API to fetch some information and display it on the page. This API call depends on a certain API header with is set by Page B. Now, let's assume my current header has the value "Value1". If I follow the below steps:

  • navigate to Page A
  • Page A loads the data with header value "Value1"
  • I navigate to Page B and change the header Value to "Value2"
  • navigate back to page A with QR.toName or QR.to
  • Page A needs to refresh and reload the data with the header "Value 2" and not maintain its already fetched data (the existing state)

If I could tell it somehow in QR.toName or QR.to functions to call the builder function again instead of returning the existing state, that would be great.

Can you please help me achieve this scenario? (I need this in my current project.)

Trying to build a tab nested navigation

Hi and thank you for this great package.
My goal is to have an app with 4 bottom tabs that each keep their own separate navigator stack.

Right now, following your docs, I have set up the home page as follows

final appRoutes = [
  QRoute.withChild(
      path: '/home',
      pageType: QFadePage(
        transitionDurationmilliseconds: 10,
      ),
      initRoute: '/feed',
      builderChild: (child) => HomeScreen(router: child),
      children: [
        QRoute(name: mainTabs[0], path: '/feed', builder: () => FeedScreen()),
        QRoute(
            name: mainTabs[1],
            path: '/workouts',
            builder: () => WorkoutsScreen()),
        QRoute(name: mainTabs[2], path: '/teams', builder: () => TeamsScreen()),
        QRoute(
            name: mainTabs[3],
            path: '/athletes',
            builder: () => ProfileScreen()),
      ]),

and have it working with some caveats:
When I tap one of my tabs, the corresponding screen is shown accordingly but I have the possibility to swipe right to go back to the previous one, which is not the expected behavior for tabs. Furthermore, swiping back doesn't update the bottomtapbar selected index.

So I tried to replace
QR.toName(mainTabs[index]);
by
QR.navigator.replaceAllWithName(mainTabs[index]);
in my onTap, which makes it "better" in terms of behavior, but I am not sure if it's the best option.

And, I don't know if this will allow me to maintain the state of each tab separately as my app will end up having

  • Feed
    • Notifications
  • Workouts
    • Workout id#
  • Teams
    • Team Id#
      • Members
        • Member ID#
      • Team Settings
  • Athletes
    • Athlete id#
    • Settings

How would you go about setting this up?

Thanks very much for your precious help on this!

Double "//" appears for Splash Screen

I get "localhost:51273/#//" for the Splash screen for the below configuration.

class AppRoutes {
List routes() => [
QRoute.withChild(name:"app", path: "/", initRoute: "", builderChild: (r)=> EmptyBaseScreen(r),children: [
QRoute(name: 'SplashScreen', path: '', builder: () => SplashScreen()),
PreLoginRoutes().routes(),
PostLoginRoutes().routes(),
])
];
}

Expected:

"/" -> SplashScreen

Dashboard example and sidebar navegation

Hi @SchabanBo,
First of all, thank you very much for the "dashboard" example, it works wonderfully well, however I have some doubts.
When I click on the sidebar options (Info, Orders, Items) the pages are created (QR.to()), but they do not replace each other,

class Sidebar extends StatelessWidget {
  const Sidebar({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => Container(
        color: Colors.grey.shade800,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ListTile(
              title: const Text('Info'),
              //onTap: () => QR.navigatorOf('/dashboard').replaceAll('/info'),
              onTap: () => QR.to('/dashboard/info'),
            ),
            ListTile(
              title: const Text('Orders'),
              //onTap: () => QR.navigatorOf('/dashboard').replaceAll('/orders'),
              onTap: () => QR.to('/dashboard/orders'),
            ),
            ListTile(
              title: const Text('Items'),
              //onTap: () => QR.navigatorOf('/dashboard').replaceAll('/items'),
              onTap: () => QR.to('/dashboard/items'),
            )
          ],
        ),
      );
}

that is, if I am on the Info page, when I click on Orders the Orders page is displayed but the info page is not disposed. This way is fine, but it can overload memory, wouldn't it be better if the pages were replaced?
However, the navigability of the back and forward buttons should be the same whether the pages are destroyed or not.
Can this be done with qlevar_router?

Again thank you very much for your help.
Regards,
Jose

Interface for clean architecture

Hi, thanks for the package. I think it would be nice if there is an abstract class or interface I can extend for clean architecture.

[Proposal] May we implement a TabPage or PageView with Qlevar?

Hello guys, I was wondering If it would be possible to get children's route act like TABS into a TabPage?

Example of the use case - MobileRoutes has three tabs

Route:

mobile_routes.dart
class MobileRoutes {
  static const String mobile = 'mobileRoute';

  static const List<Tab> tabs = <Tab>[
    Tab(text: 'Mobile stores'),
    Tab(text: 'Mobile products'),
    Tab(text: 'Mobile settings'),
  ];

  final route = QRoute.withChild(
      path: '/mobile',
      name: mobile,
      initRoute: '/stores',
      builderChild: (router) => MobileView(router),
      children: [
        QRoute(
          path: '/stores',
          pageType: QFadePage(),
          builder: () => MobileStoresView(),
        ),
        QRoute(
          path: '/products',
          pageType: QFadePage(),
          builder: () => MobileProductsView(),
        ),
        QRoute(
          path: '/settings',
          pageType: QFadePage(),
          builder: () => MobileSettingsView(),
        ),
     ]);
}

Widget:

mobile_view.dart
class _MobileViewState extends State<MobileView> {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController =
        TabController(length: MobileRoutes.tabs.length, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            controller: _tabController,
            tabs: MobileRoutes.tabs,
          ),
        ),
        body: TabBarView(controller: _tabController, children: [
          MobileStoresView(),
          MobileSettingsView(),
        ]),
      );
}

And thank you so much guys, having a nice day!

Contextual help

Hi @SchabanBo,
It would be very nice if the contextual help showed some explanation of how a class, function or parameter works.
2021-11-28_21-14-17

2021-11-28_21-15-17

Thanks.

Mobile App : onBackbutton Pressed Navigate to previous route

Hii @SchabanBo ,

I have 3 pages (/signup), (/login) and (/user/dashboard), once I signedUp and login
In the mobile app, when I pressed back button it navigates to login Page then again I pressed back button it navigates to /signup Page
Any Solution to Close/exit the app if the user clicks back button from Dashboard?

Page Results

Hi @SchabanBo,

I am wondering how can I get results from a page. There are cases where a page is there to calculate something and return it to the caller. I couldn't fine any example for this use case. Or did I miss something?

Thanks

Problem defining 2 different QRouterDelegates

Hey @SchabanBo,

First I wanna thank you for the amazing work.
I have a special case in my app, which when it runs for web or tablets it split the screen in half and in the left part presents a preview of the app as it will be running in mobile.
For that reason I use the DevicePreview lib where I define the MaterialApp.router with his own QRouterDelegate and routes which are different than the top level MaterialApp.router which also has it's own QRouterDelegate and routes.
The problem is that the 2 different QRouterDelegate are not indented and when a navigation from the left QRouterDelegate happens it update the top level QRouterDelegate and change his path also.

Is there any way I can make the 2 QRouterDelegate behave independently?

Thanks in advance.

I feel like I'm doing this wrong for nested routing

Hello again,

I'm trying to get my routing to work with the url ids, yet it feels like I'm doing something wrong because of the way I have to transition to the children pages.

Rotues

    QRoute(
      path: '/testKit/results/:resultId',
      builder: () => Screen1(resultId: findParameter<String>('resultId')),
      children: [
        QRoute(
          path: 'stuff/:stuffId',
          builder: () => Screen2(stuffId: findParameter<String>('stuffId')),
        ),
      ],
    ),

Now to get to the test kit route I do a await QR.to('/testKit/results/be11146a-18a1-4c46-bf6b-d76aa16b5546'); and this seems to work great.

Then I try to go to the stuff child screen of the testKit screen, but if I do a await QR.to('stuff/1234'); then I get an error of [stuff] is not child of Key: [-1](Root). I thought a relative path should work under this circumstance.

To get this to work I had to do a await QR.to('${QR.currentPath}/stuff/1234'); and now it works.

This feels wrong though, am I doing something wrong or is this the intended way to access children routes?

Thank you,
Michael

Non-used confused parameter in QRouterDelegate

I noticed the parameter notFoundPage in QRouterDelegate which is not used. And this is confusing a little as I tried to set my value for this parameter and got nothing. Is it required for new functionality or is it forgotten to remove?

Is it possible to refresh the whole page when changing nested route?

My routes are organized like this:

class AppRoutes {
  final routes = <QRouteBase>[
    QRoute(
        path: '/main',
        page: (childRouter) => PageMain(router: childRouter),
        children: [
          QRoute(path: '/apps', page: (child) => PageAppManage()),
          QRoute(path: '/home', page: (child) => PageHome()),
          QRoute(path: '/app/:id', page: (child) => PageAppDashboard()),
          QRoute(path: '/app/edit/:id', page: (child) => PageAppEdit()),
          QRoute(path: '/app/cfg/:id', page: (child) => PageAppConfig()),
          QRoute(path: '/app/img/:id', page: (child) => PageAppImage()),
          QRoute(path: '/app/op/:id', page: (child) => PageAppEdit()),
        ]),
    QRoute(path: '/login', page: (childRouter) => PageLogin()),
    QRoute(path: '/404', page: (childRouter) => Placeholder())
  ];
}

From my understanding,
'/main' is responsible for building the PageMain widget, while its nested routes are responsible for building Inner Widgets.

So if I change the :id in the nested URL, the inner widgets get updated, but the PageMain won't.

What I want is to make PageMain also update when the nested URL changes.

I'll try to explain this with an example:
If I navigate from '/main/apps' to '/main/app/1',
The PageAppManage can switch to PageAppDashboard correctly.
But PageMain won't get updated because it is not a part of the nested router, it's the parent router of it.

I can get the param :id within PageMain, but the page won't update if I change the param.

PageMain still needs to be updated in my case, like highlighting the selected item from the menu or change the index of a combo box in the PageMain.

I also thought it could be done not to use the nested route, but it would make the route tree unorganized - the routes are all on the same level, and I have to make each route use PageMain and handle the inner pages accordingly.

BTW, I really appreciate your work on this package. It makes the navigation much much easier than the official one. Thank you!

[Question] useListenable() in flutter_hooks is supported?

I am converting the example with useListenable in flutter_hooks.

class HomePage extends HookWidget {
  final QRouter _router;

  const HomePage(this._router, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final _navi = useListenable(_router.navigator);
    // ignore: avoid_print
    print(_navi.currentRoute.name);

    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
        centerTitle: true,
        actions: [
          IconButton(
            onPressed: () {
              AuthState.isAuthed = false;
              QR.navigator.replaceAll('/login');
            },
            icon: Icon(Icons.logout),
          )
        ],
      ),
      body: _router,
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'home'),
          BottomNavigationBarItem(icon: Icon(Icons.store), label: 'store'),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: 'Settings',
          )
        ],
        currentIndex: AppRouter.tabs
            .indexWhere((element) => element == _router.routeName),
        onTap: (v) => QR.toName(AppRouter.tabs[v]),
      ),
    );
  }

And, facing this exception on logout.

flutter: QR: Finding Match for /login under root
flutter: QR: Navigator with name [/home] was removed
flutter: QR: adding Route: Key: [0](/login), Full Path: /login to the navigator with Key: [-1](Root)

══║ EXCEPTION CAUGHT BY HOOKS LIBRARY β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
The following assertion was thrown while disposing _Entry<HookState<dynamic, Hook<dynamic>>>:
A QRouterController was used after being disposed.
Once you have called dispose() on a QRouterController, it can no longer be used.

When the exception was thrown, this was the stack:
#0      ChangeNotifier._debugAssertNotDisposed.<anonymous closure> (package:flutter/src/foundation/change_notifier.dart:114:9)
#1      ChangeNotifier._debugAssertNotDisposed (package:flutter/src/foundation/change_notifier.dart:120:6)
#2      ChangeNotifier.removeListener (package:flutter/src/foundation/change_notifier.dart:233:12)
#3      _ListenableStateHook.dispose (package:flutter_hooks/src/listenable.dart:75:21)
(SNIP)
#125    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:259:5)
#126    _drawFrame (dart:ui/hooks.dart:127:31)
(elided 3 frames from dart:async)

Functionally this app (https://github.com/chunghha/fl_router_poc) works with HookWidget even if the exception above occurs including re-login.

@SchabanBo could you take a look further? I think the exception is related to this line of code "QR.navigator.replaceAll('/login');". However, I am not sure about where between my code, this package or flutter_hooks to fix. If you'd give an insight, that would be a help.

Back navigation from nested screen

First of all, thanks for the package, it works great and it's pretty simple to use and implement. And the middleware feature rocks.

After setting it in my project I am facing an issue. Given the following code:

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

void main() => runApp(App());

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

  @override
  Widget build(BuildContext context) => MaterialApp.router(
    routeInformationParser: const QRouteInformationParser(),
    routerDelegate: QRouterDelegate(
      _router,
      initPath: '/home',
    ),
  );

  static final _router = [
    QRoute.withChild(
      name: 'home',
      path: '/home',
      builderChild: (router) {
        return Container(
          child: router,
        );
      },
      initRoute: '/login',
      children: [
        QRoute(
          name: 'home_login',
          path: '/login',
          builder: () {
            return Center(child: MaterialButton(
              child: Text('Go to vendor login'),
              onPressed: () { QR.to('/vendor'); },
            ),);
          },
        ),
      ],
    ),
    QRoute.withChild(
        name: 'vendor',
        path: '/vendor',
        builderChild: (router) {
          return Container(
            child: router,
          );
        },
        initRoute: '/login',
        children: [
          QRoute(
            name: 'vendor_login',
            path: '/login',
            builder: () {
              return Text('Vendor login');
            },
          ),
        ]
    )
  ];
}

Once you go to login (/vendor/login) inside vendor page from login (/home/login) in home page, you can't pop back. If you do it, the web url updates but the widget remains, unless you pop twice.

allow pages to stop from navigating away, e.g. if there are unsaved state changes

Hello,
I am going to start a web project with Flutter, for another project use the Fluro library, however, I could not solve the following problem:
If a user is on a page that contains a form and is making modifications is said form, I would like that if he tries to exit without having saved the modifications (either by putting another url, with the browser's backbutton, ...) it would show him an alertdialog giving him the possibility of canceling the navigation to the new url or, on the contrary, of canceling the modifications and staying on the same page where he is.
The question is, can I do this with qlevar_router?
qlevar_router has any mechanism by which this functionality can be achieved?
Please, if this functionality is possible with qlevar_router could you give me some indications.
Thank you so much for all the help.
Regards,
Jose

how to pass data from a class (screen/page) to instance of another?

how to pass data from a class (screen/page) to instance of another?

something as:

QRoute(path: '/book/:id((^[0-9]\$))', builder: (Map data) => const BookDetailsScreen(data.book))
QR.to('/book/${state[item].id}', data: {book: BookModel(id: '1', title: 'Kindred', author: 'Octavia E. Butler')})

Dashboard sidebar onTap to restore page nested state

Really appreciate this great package and the excellent example πŸ’― πŸ‘ πŸ˜„

I would like to know how this package can work in this scenario:

  1. run the example in this repo
  2. already login and click sidebar stores to http://localhost:57974/#/dashboard/stores
  3. do some subpage, finally stay at http://localhost:57974/#/dashboard/stores/3/product/6
  4. click sidebar nav to home http://localhost:57974/#/dashboard/home
  5. nav back to stores by click sidebar, for now it would be http://localhost:57974/#/dashboard/stores

Would it be possible to nav back to http://localhost:57974/#/dashboard/stores/3/product/6 ?
in sidebar_section.dart
onTap: () {
QR.to('dashboard/stores');
},

how can I easily nav to last sub page navigation ex. (dashboard/stores/xxx/xxx/xxx/xx)?

Thank you a lot for creating suck great package !!

QCupertinoPage has shadows

After a lot of debugging, I found that the QCupertinoPage has some sort of shadow to its boundaries. Is there any option of removing them?

Async functionality of canPop

Hey @SchabanBo,

I'd like to thank you for the great package.

I wonder if it is possible to make canPop method in QMiddleWare be able to work asynchronously.
This can be useful when I need to confirm if the user wants to leave the screen with dialog, for example.

QRoute.withChild Navigation issue

Hii @SchabanBo
I referred this example https://github.com/SchabanBo/qr_samples/blob/main/lib/common_cases/dashboard.dart
and created the same structure like signup, login, and Dashboard(with child route)
I have a sidebar in my site that has sub-routes like Dashboard/info, Dashboard/contact ..etc when I click those items it navigates to the corresponding page, in my case this scenario does not work sometimes

package version: 1.1.3
issue faced:
navigate to child-1
navigate to child-2
navigate to child-3
This child1 roue,child2 route,child3 route navigations are in static fixed sidebar
then I navigate to child-1 but it navigates to child-2, child pages did not get Refresh sometimes
routing Sometimes not works in QRoute.with child

In Each child page I call API in init state. but sometimes navigations not starts from init state so i have to manually refresh whole page to recall API

Top level path with same path prefix will lead to 'Page Not Found'

So after issue #2, I'd like to try another solution that makes all routes to the top.
The routes look like:

class AppRoutes {
  final routes = <QRouteBase>[
    QRoute(
        path: '/main/apps',
        page: (child) => PageMain(child: PageOther(),)),
    QRoute(
        path: '/main/home',
        page: (child) => PageMain(child: PageOther(),)),
    QRoute(
        path: '/main/app/:id',
        page: (child) => PageMain(child: PageOther(),)),
    QRoute(
        path: '/main/app/edit/:id',
        page: (child) => PageMain(child: PageOther(),)),
    QRoute(
        path: '/login',
        page: (child) => PageMain(child: PageOther(),)),
    QRoute(
        path: '/404',
        page: (child) => PageMain(child: PageOther(),)),
  ];
}

But only checked path could be found:

  • /main/apps
  • /main/home
  • /main/app/:id
  • /main/app/edit/:id
  • /login
  • /404

So my quick guess is the same prefix /main lead to this issue.

I'm expecting the path could match to its page if not using nested router. So I thought this behavior is not correct.

I made a repro project for you to test:
https://github.com/rockingdice/qr_issue_repro

Dashboard example and check current page

Hi @SchabanBo,
When I am in one of the dashboard pages (for example, orders), how could the corresponding option be illuminated in the sidebar?
Also, if I am in one of the pages (for example, orders) and I click on the same option I would not want the page to be recreated again.
Can you do all this with qlevar_router?
Thanks for your help.
Regards,
Jose

onWillPop callback not called when back button is pressed on WillPopScope Widget

I am trying to override the back button behaviour for use with a TabController, where the back button will navigate to a certain tab, yet I am unable to do this using WillPopScope & onWillPop().

I have tried this without qlevar and it would work, yet when using the router onWillPop() is never called. Is this intended behaviour, and if so how would I implement this functionality while using qlevar?

The Widget I am try to use is as follows:

Scaffold(
        body: TabBarView(
        controller: tabController,
        children: [
          WillPopScope(child: HomeScreen(), onWillPop: () async {
            tabController.animateTo(0, duration: Duration(milliseconds: 500),);
            return false;
          }),
          WillPopScope(child: FriendScreen(), onWillPop: () async {
            tabController.animateTo(0, duration: Duration(milliseconds: 500),);
            return false;
          }),
          GroupScreen()
        ],),
        bottomNavigationBar: ConvexAppBar(
          controller: tabController,
          style: TabStyle.textIn,
          items: [
            TabItem(icon: Icons.home, title: 'Home'),
            TabItem(icon: Icons.map, title: 'Friends'),
            TabItem(icon: Icons.add, title: 'Groups'),
          ],
          onTap: (int i) => {
            print(QR.history.debug())
          },
        )
    )

Page Transition Example

Hi, Thanks for the great navigation package. I am struggling with implementing fade Transition for the routes. Can you point me to any example for the same or provide one example here.

nested routes with similar path bug

Hello, I have been testing this library lately and everything looks amazing, except for this bug that I just found. Well I'm not sure if this is a bug or an expected behavior.
basically if you have nested routes like this.

      QRoute.withChild(
        path: '/home',
        initRoute: '/grid',
        builderChild: (child) => PostRouteWrapper(
          child: child,
        ),
        children: [
          QRoute(
            path: '/grid',
            builder: () => const PostScreen(),
          ),
          QRoute(
            path: '/grid/:index',
            builder: () => const PostDetailScreen(),
          )
        ],
      );

If you try to navigate to /grid/index (of course with full path so like this /home/grid/2). It breaks and throw this error.

I/flutter (12458): QR: Finding Match for /home/grid/2 under root
E/flutter (12458): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Null check operator used on a null value
E/flutter (12458): #0      MatchController.match
package:qlevar_router/…/controllers/match_controller.dart:73
E/flutter (12458): <asynchronous suspension>
E/flutter (12458): #1      QRContext.toName
package:qlevar_router/src/qr.dart:138
E/flutter (12458): <asynchronous suspension>
E/flutter (12458):

I have try to debug this error, but I just can't I'm new to flutter and well I'm not experience enough to even know what is the exact problem.

Customize or remove Loading blank page

Hi guys!
Im trying to find out how to customize the blank page with a centered "loading" at the app opening (probably the Qlevar router startup), but I couldnt found.
I liked a lot this package.
Can you help me with that?
Thanks in advance

[Feature Request] Add onWillPop callback before navigating to other routes

The scenario I want to implement is a form for data modification, if a user wants to change to other pages before submitting any contents, he will get a warning dialog. After the confirmation, the navigator continues the routing or cancels the action.

Don't know if that's possible. I have only used navigator 1.0 on the mobile platform and usually, I'll use a WillPopScope widget for handling the back button event.

I tried to put WillPopScope on the page, but it's not working when I'm navigating to other routes.

Navigation challenges

Hello again @SchabanBo,

I have a issue where I need my screen to refresh, but since it's already in the history stack it does not reload. I've read #27 but I am having a hard time understanding how I should accomplish the following.

My navigation example:

  1. /start
  2. /test/results/:resultId - QR.to('/test/results/111') - βœ”οΈ loads properly
  3. /test/results/:resultId/stuff/:stuffId - QR.to('/test/results/111/stuff/222') - βœ”οΈ loads properly
  4. /test/results/:resultId/otherDetails/:otherDetailsId - QR.to('/test/results/111/otherDetails/333') - βœ”οΈ loads properly
  5. /test/results/:resultId/stuff/:stuffId - QR.to('/test/results/111/stuff/999') - ❌ doesn't build again

The problem is, on # 5 the stuff screen doesn't reload because it's already been loaded.

I need both pieces of information, the 111 and the 999 so that I can display the screen correctly but I also need it to rebuild the screen with these new parameters.

You suggest to use QR.replace(path, withPath) but in this example I'm not sure what values I should use. Can you tell me what you would do in this case to get # 5 to re-load the screen?

Thank you,
Michael

QRoute.withChild monted to / not worked.

Example routes config:

final routes = [
    QRoute.withChild(
        name: AdminRoute,
        path: '',
        builderChild: (child) => AdminPage(child),
        initRoute: 'dashboard',
        children: [
          QRoute(
              name: 'dashboard',
              path: 'dashboard',
              builder: () => DashboardPage()),
          QRoute(
              name:  'settings',
              path: 'settings',
              builder: () => SettingsPage())
        ])
  ];
];

When I try to navigate to QR.toName('settings') I got the Dashboard page instead of the Settings page.

Log:

QR: Finding Match for //settings under root
QR: Navigator with name [admin] was removed
QR: adding Route: Key: [0](admin), Full Path: / to the navigator with Key: [-1](Root)
QR: Finding Match for dashboard under path /
QR: adding Route: Key: [1](dashboard), Full Path: //dashboard to the navigator with Key: [8](admin)

Access context inside of middleware

Hi @SchabanBo !

Great package, I had a quick question. For the route guard, is there a way to get the context? Please see the example below:

middleware: [
  QMiddlewareBuilder(redirectGuardFunc: () async {
    // instead of relying oh AuthService, is it possible to rely on a AuthBloc? I would need
    // access context though
    return await AuthService().isLogged ? null : '/login';
  })
],

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.