Deep linking with passing objects to the new page - flutter

I'm trying to implement deep linking in my web app but I also need to pass some objects to the newly opened page. I found this documentation
https://docs.flutter.dev/cookbook/navigation/named-routes where it says I need to define routes in the MaterialApp which is understandable but in the example where they initiate a page change they only use the route name and it doesn't seem to be possible to pass an object to the page widget.
Navigator.pushNamed(context, '/second');
What I'm doing for now opens a new page widget and the new widget receives an object as an argument but this doesn't support deep linking.
My OrdinaryButton class:
OrdinaryButton({super.key, this.text, this.goto}); // the goto argument gets an instance of the next page to go to
Widget? goto;
...
Navigator.push(context, MaterialPageRoute(builder: (context) => goto!));
How can I implement deep linking with passing objects to the new page (preferably without any extra Flutter packages)?

Related

How to return some data from a page in flutter using Navigator 2.0?

I'm using flutter navigator 2.0 in my app and I'm trying to return some data from another screen when it pops. Here's the code for the same:
This is what I'm using to push/add a new page. After the user has made changes to the edit profile page, I'm trying to update the data on the existing page (profile page).
appState.currentAction = PageAction(
state: PageState.addPage,
widget: EditProfile(currentUserId: currentUserId),
page: Edit_Profile_PageConfig,
);
After the changes are made on the edit profile page, this is what I'm doing to pop:
appState.currentAction = PageAction(state: PageState.pop);
But I'm not sure how can I pass the data from the edit profile page back to the profile page. In the old navigator style, it was pretty easy to have a then function, like this:
var callBack = await Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => EditProfile( )));
But I'm not sure how to achieve this using Navigator 2.0. I referred to these two references for developing the navigation in the app.
Flutter Navigator 2.0
Google Docs
when calling navigator.pop add your data as a second argument.
Navigator.pop(context, data);

Flutter detect when Navigator is ready

Working on a Flutter app, I am handling deeplinks with a SDK for which I am given a listener that I must handle as soon as the app starts, therefore in the main().
Once a deeplink is received, I must navigate to the proper screen, based on the parameters passed along the deeplink data.
Since I receive the deeplink in the main function, I am detached from the Context of the app, therefore to access the NavigatorState I used a navigation singleton with a GlobalKey passed to my CupertinoApp's navigatorKey. I later use this key to retrieve the NavigatorState and call push. (instead of Navigator.of(context)....
However, if opening the app from a deeplink, it is very likely that the navigatorKey does not contain anything (yet).
How can I detect/wait until the Navigator is ready ?
As of right now my approach is to add a WidgetsBinding.instance.addPostFrameCallback in my App's initState, that resolves a promise to indicate when the GlobalKey pointing to the NavigatorState can be used... I'm sure there is a beter way to achieve this.
For this i make the initialRoute as a Loading screen and execute all my logic inside it , that way i can have different initialRoutes and i don't have to worry about not having MediaQuery, or Navigator, or even ThemeData.
However the question specifies a way to know if the navigator is available, for this i would use the builder function of MaterialApp/WidgetsApp/CupertinoApp, it's used to override the navigator altought i use it to add pading and a global background color and even override the navigator widget with a custom one,
CupertinoApp(
...
builder: (context, child){
//The navigator is ready
Future.delayed(Duration.zero,
() => print(navigatorKey.currentContext)); //We use a delayed since the child needs to be returned first. It's kinda like a hack 7u7
return child;
}

How to refresh the page when user comes back to it from any other page using back key?

I have a page which is calling multiple classes and different widgets
and by clicking on it user can hop to any page.
Currently the issue is I want to refresh the original page everytime it is shown to user.
When it is freshly loaded (causing no issue for now).
When user comes back to it from some other page using back key.
old data is shown on the page, which I am trying to get rid of.
I have tried using Navigator.push method (Observer class method) and tried to listen when user presses backkey.
but there are multiple pages serving unique requests and I don't want to link everyone with that first page.
as while clicking Navigator.pop(context) method i'll have to pass some string.
Does any one know
how can I refresh the page when users comes back to it using backkey.
Navigator.push returns a Future when the MaterialPageRoute passed into it is resolved. You could await that Future to know when some other view has popped back to it.
Example,
Navigator.of(context).push(MaterialPageRoute(
builder:
(context) => NewView(),
),
).then((_) {
// Call setState() here or handle this appropriately
});
Had the same issue, the following worked for me (below code is in FirstPage()):
Navigator.push( context, MaterialPageRoute( builder: (context) => SecondPage()), ).then((value) => setState(() {}));
After you pop back from SecondPage() to FirstPage() the "then" statement will run and refresh the page.
NavigatorObserver can listen to route changes.
You need to create your implementation overriding didPop, didPush etc.
Then you can pass it to navigatorObservers field of MaterialApp or Navigator

Calling Navigator.of anywhere without context?

I've been setting up a tabbed navigation app based on this wonderful tutorial (https://medium.com/coding-with-flutter/flutter-case-study-multiple-navigators-with-bottomnavigationbar-90eb6caa6dbf).
Now I would like to display a modal overlay login route that covers the whole screen. My login controller checks if the user is logged in and I would like to fire an event on which the modal login route appears. The problem I have is now, that I don't have a context object where I receive the signal to display the login route:
Navigator.of(context).pushReplacementNamed('/');
How can I solve this or is this the wrong approach?
My User controller is a singleton object that gets initiated at app start. It checks then the user data model and if that is not set, it wants to invoke the login screen / route.
Thanks for any pointer in the right direction.
Martin
Define a navigator key that accesses from everywhere in-app (e.g in main class global space ) and pass it to root MaterialApp navigator key property in the build method
final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
then :
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
//...
);
}
then you can access context everywhere with doing like this:
navigatorKey.currentContext
example of navigating:
Navigator.of(navigatorKey.currentContext).pushReplacement(
MaterialPageRoute(builder: (_) => SecondScreen()));
You could use a globalKey to access the context of the widget u like (you have to pass it a key in the constructor) , and leave it in the global space, or static in any class....
although not the most elegant approach, should work
you can use this package to skip the required context.
https://pub.dev/packages/one_context
// go to second page using named route
OneContext().pushNamed('/second');
// go to second page using MaterialPageRoute
OneContext().push(MaterialPageRoute(builder: (_) => SecondPage()));

InheritedWidget not accessible from new Route

I'm building a basic Flutter app with Bloc pattern. This is my structure so far.
MainProvider contains the Repository, which I can pass in every Bloc of every sub page (one Bloc per page, basically).
The problem is that, if I want to access MainProvider like this:
final provider = MainProvider.of(context);
from MenuPage, or OtherPage, which I access to by navigating from HomePage with
Navigator.push(context,
MaterialRoutePage(
(context) => MenuPage(homePageParam); //or OtherPage(homePageParam)
);
the .of method returns null.
How can I properly access that InheritedWidget? Should I do another type of Navigator.push?