Comments (13)
Hey @frank06, yes. You're not supposed to use the canNavigate func manually,
Just let your guard do the redirecting for you like follows
class AuthGuard extends RouteGuard {
@override
Future<bool> canNavigate(
BuildContext context, String routeName, Object arguments) async {
if (!isAuthenticated) {
Router.navigator.pushNamed(Router.loginScreen)
return false;
}
return true;
}
}
You could have the guard await for the LoginRoute results and return true if user logs in successfully so you still navigate to your secure route after
Future<bool> canNavigate(
BuildContext context, String routeName, Object arguments) async {
if (!isAuthenticated) {
var authenticated await Router.navigator.pushNamed(Router.loginScreen);
// if authenticated is true you still navigate to your secure route
return authenticated;
}
return true;
}
Next annotate your secure routes with GuardedBy([AuthGuard]) and pass in your guards as types.
class $Router {
@initial
HomeScreen homeScreen;
@GuardedBy([AuthGuard])
SecureScreen secureScreen;
@GuardedBy([AuthGuard])
SecondScreen2 secondScreen2;
LoginScreen loginScreen;
}
now any route annotated with @GuardedBy will go through the assigned guards before it can navigate to its destination.
Hope this helps.
from auto_route_library.
Great, thanks @Milad-Akarie !
I am not able to make this work with my screen design (slightly different than yours):
In my app there are NO public screens (i.e. all screens, except LoginScreen
should be guarded by AuthGuard
). My users have to be logged in to see the home page.
My issue is that canNavigate
is never called with the following setup.
Why?
import 'package:auto_route/auto_route.dart';
import 'package:auto_route/auto_route_annotations.dart';
import 'main.dart';
@MaterialAutoRouter()
class $Router {
@initial
@GuardedBy([AuthGuard])
HomeScreen homeScreen;
// @CustomRoute(returnType: bool)
LoginScreen loginScreen;
}
class AuthGuard extends RouteGuard {
@override
Future<bool> canNavigate(context, routeName, arguments) async {
throw UnsupportedError('never reaches this');
return true;
}
}
import 'package:auto/router.dart';
import 'package:flutter/material.dart';
import 'router.gr.dart';
void main() {
Router.navigator.addGuards([AuthGuard()]);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Auto example',
theme: ThemeData(primarySwatch: Colors.amber),
onGenerateRoute: Router.onGenerateRoute,
navigatorKey: Router.navigator.key,
initialRoute: Router.homeScreen,
);
}
}
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text('login page'));
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text('secure area'));
}
}
from auto_route_library.
Unfortunately, the navigator widget within the MaterialApp is the one pushing the initial route, so there's no way to intercept and guard it with the current approach.
You could always have a public initial route that shows a loading indicator or something until the real distention is decided.
then in the initial route push and replace the current route with your secureScreen
void initState() {
Router.navigator.pushReplacementNamed(Router.secureScreen);
super.initState();
}
from auto_route_library.
Thanks!
I ended up calling this stateful widget RedirectRoute
, and using it like so:
MaterialApp(
title: 'Auto example',
theme: ThemeData(primarySwatch: Colors.amber),
onGenerateRoute: Router.onGenerateRoute,
navigatorKey: Router.navigator.key,
home: RedirectRoute(Router.homeScreen),
),
@MaterialAutoRouter()
class $Router {
@GuardedBy([AuthGuard])
HomeScreen homeScreen;
@CustomRoute(returnType: bool)
LoginScreen loginScreen;
}
class AuthGuard extends RouteGuard {
@override
Future<bool> canNavigate(context, routeName, arguments) async {
var auth = Provider.of<AuthState>(context);
if (!auth.value) {
auth.value = await Router.navigator.pushNamed(Router.loginScreen);
}
return auth.value;
}
}
It does work fine (successfully triggers canNavigate
), with a caveat.
There can't be a route decorated with @initial, as it seems the home
route must be treated like /
somewhere and that ends up in an infinite loop.
Also, since the login page communicates success/failure via pop<bool>
, the login page always shows a back button in Material. When opening the app the first time and seeing the login screen, clicking on the back button throws an exception.
_AssertionError (Failed assertion: boolean expression must not be null)
(https://github.com/Milad-Akarie/auto_route_library/blob/master/auto_route/lib/src/extended_navigator.dart#L101)
That said I'd LOVE an API like:
class $Router {
@initial
@GuardedBy([AuthGuard])
HomeScreen homeScreen;
@CustomRoute(returnType: bool)
LoginScreen loginScreen;
}
with an initialization like:
MaterialApp(
title: 'Auto example',
theme: ThemeData(primarySwatch: Colors.amber),
onGenerateRoute: Router.onGenerateRoute,
navigatorKey: Router.navigator.key,
home: Router.initialRoute,
),
(initialRoute
redirect widget provided by the library?)
And no back button issues with the login screen.
Loving the library so far. Thanks.
from auto_route_library.
Hey @frank06, I don't think it's a good idea to work with widgets and named routes at the same time, why can't the initial route (The Redirect Widget) be named?
Navigator will automatically push the initial route you pass to material App which defaults to "/" if you don't pass anything. then inside of the initial route push your guarded route as a REPLACEMENT so the initial route is poped first.
from auto_route_library.
why can't the initial route (The Redirect Widget) be named?
Because a widget accepts a parameter (the redirect "to" route name). Afaik this is not possible with a named route? So I would have to make a specific stateful widget just for redirecting (with a hardcoded route), and add it to the routing configuration. My intention was to make this easier and more generic.
My app doesn't show the Material back button anymore – so not a problem for me. But I think there's still an issue there.
from auto_route_library.
Thank you for your help @Milad-Akarie
from auto_route_library.
Hey, @frank06 what did you end up doing?
from auto_route_library.
I ended up doing this, works great so far!
onGenerateRoute: Router.onGenerateRoute,
navigatorKey: Router.navigator.key,
home: RedirectTo(Router.dashboardScreen),
from auto_route_library.
How does the RedirectTo Widget look like?
from auto_route_library.
class RedirectTo extends StatefulWidget {
final String redirectTo;
const RedirectTo(this.redirectTo, {Key key}) : super(key: key);
@override
_RedirectToState createState() => _RedirectToState();
}
class _RedirectToState extends State<RedirectTo> {
@override
void initState() {
Router.navigator.pushReplacementNamed(widget.redirectTo);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Loading ${widget.redirectTo}...'),
),
);
}
}
from auto_route_library.
I believe that the navigator will still automatically navigate to '/' even if you specify a home widget. This will cause your dashboard to be called twice! right?
from auto_route_library.
I just put a breakpoint on DashboardScreen#build
and it stops only once.
As far as I understand, MaterialApp
will use either home
OR initialRoute
from auto_route_library.
Related Issues (20)
- App crashes when trying to navigate from modal, which is animating. HOT 1
- Udpate documentation for Autoroute Declaritive Routing HOT 1
- Redirect is not working in `AutoRouteGuard` HOT 8
- Navigate Function causes clearing for path params HOT 1
- AutoLeadingButton custom semantic label
- onNavigation guard causes Stack Overflow
- In NESTED NAVIGATION the pages overlap in the transition HOT 1
- infinite loop on context.router.pop()
- AutoTabsRouter testecase fail. HOT 4
- Initial page created when homeIndex is set differently
- add shallow routing
- Functionality to control route changes
- Functionality to control route changes HOT 4
- Unhandled Exception: type 'AutoRoutePage<dynamic>' is not a subtype of type 'AutoRoutePage<Object>' in type HOT 2
- Inherited params not working and wrong navigation HOT 1
- Generator uses absolute paths which generates an error in my app
- Route back to initial splash page every time I save. HOT 3
- Infinite loop in context.router.push() HOT 2
- Deep link navigation with AutoTabsScaffold; Consider making PlatformDeepLink constructor public
- Numbered lists don't render in README
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from auto_route_library.