Comments (3)
In case more code is relevant to understand the issue, here you have my raw AppRouter:
It contains custom functions and stuff such as Debug.log which are "prints".
import 'dart:convert';
import 'package:auto_route/auto_route.dart';
import 'package:bondy/V2/modules/analytics/analytics_service.dart';
import 'package:bondy/V2/modules/chat_v3/service.dart';
import 'package:bondy/V2/modules/global/global_data_service.dart';
import 'package:bondy/V2/modules/maintenance/service.dart';
import 'package:bondy/V2/modules/router/guards/auth_guard.dart';
import 'package:bondy/V2/modules/router/guards/debug_guard.dart';
import 'package:bondy/V2/modules/router/guards/pre_login_guard.dart';
import 'package:bondy/V2/modules/router/router.gr.dart';
import 'package:bondy/V2/modules/update/service.dart';
import 'package:bondy/V2/utils/library.dart';
import 'package:flutter/widgets.dart';
@AutoRouterConfig(replaceInRouteName: 'Page,Route') //"HomePage" will be generated as "HomeRoute" because of the replaceInRouteName property
class AppRouter extends $AppRouter implements AutoRouteGuard {
BuildContext? get context => super.navigatorKey.currentContext;
static final AppRouter _instance = AppRouter.internal(GlobalKey<NavigatorState>());
AppRouter.internal(GlobalKey<NavigatorState> navigatorKey) : super(navigatorKey: navigatorKey);
factory AppRouter() => _instance;
@override
List<AutoRoute> get routes => [
AutoRoute(page: HomeRoute.page, path: "/", guards: [PreLoginGuard(), AuthGuard()]),
AutoRoute(page: ForceUpdateRoute.page, path: "/update"),
AutoRoute(page: MaintenanceRoute.page, path: "/maintenance"),
AutoRoute(page: AuthRoute.page, path: "/auth"),
AutoRoute(page: ProfileRoute.page, path: "/profile/:userId", guards: [AuthGuard()]),
AutoRoute(page: PeopleRoute.page, path: "/people", guards: [AuthGuard()]),
AutoRoute(page: LiveRoute.page, path: "/lives", guards: [AuthGuard()]),
AutoRoute(page: PlanRoute.page, path: "/plan/:planId", guards: [AuthGuard()]),
AutoRoute(page: SettingsRoute.page, path: "/settings", guards: [AuthGuard()]),
AutoRoute(page: DevToolsV2Route.page, path: "/dev-tools", guards: [DebugGuard()]),
AutoRoute(page: EmptyRoute.page, path: "/empty"),
AutoRoute(page: WebViewRoute.page, path: "/web-view", guards: [AuthGuard()]),
AutoRoute(page: MapRoute.page, path: "/map"),
AutoRoute(page: ChatV3ListsRoute.page, path: "/chats", guards: [AuthGuard()]),
AutoRoute(page: ChatV3Route.page, path: "/chat/:cid", guards: [AuthGuard()]),
AutoRoute(page: PreLoginRoute.page, path: "/pre-login"),
AutoRoute(page: LogoutRoute.page, path: "/logout"),
RedirectRoute(redirectTo: '/', path: "*"), // https://github.com/Milad-Akarie/auto_route_library#wildcards
];
@override
void onNavigation(NavigationResolver resolver, StackRouter router) {
if (resolver.route.name == ForceUpdateRoute.name || resolver.route.name == MaintenanceRoute.name) {
resolver.next();
} else {
if (MaintenanceService().isMaintenance) {
resolver.redirect(const MaintenanceRoute(), replace: true);
} else if (!UpdateService().isVersionValid) {
resolver.redirect(const ForceUpdateRoute(), replace: true);
} else {
resolver.next();
}
}
}
static Uri planDeepLink(String planId) {
return Uri(
scheme: GlobalDataService.webUrl.scheme,
host: GlobalDataService.webUrl.host,
path: "/plan/$planId",
);
}
removeAllPlanRoutesOf({required String planId}) {
removeWhere((route) {
return route.name == PlanRoute.name && (route.args as PlanRouteArgs).planId == planId;
});
}
removeAllChatRoutesOf({String? chatCid, String? planId}) {
Debug.logAssertion("removeAllChatRoutesOf: chatId and planId cannot be null at the same time", showIf: chatCid == null && planId == null);
chatCid ??= "${ChatType.plan.value}:${planId!}";
removeWhere((route) {
if (route.name == ChatV3Route.name) {
final ChatV3RouteArgs args = route.args as ChatV3RouteArgs;
return (args.cid == chatCid) || (args.channel?.cid == chatCid);
}
return false;
});
}
Future<void> rebuildAll() async {
List<RouteData> routesDataList = stack.map((e) => e.routeData).toList();
List<PageRouteInfo<dynamic>> routeInfos = routesDataList.map((routeData) => PageRouteInfo.fromMatch(routeData.topMatch)).toList();
if (routeInfos.isNotEmpty) {
await popAllAndPushAll(routeInfos);
}
}
Future<void> popAllAndPushAll(List<PageRouteInfo<dynamic>> routeInfos) async {
List<RouteData> routesInStack = stack.map((e) => e.routeData).toList();
Debug.logAssertion("No routes to pop", showIf: routesInStack.isEmpty);
Debug.log("Popping all routes (${routesInStack.map((e) => e.name).join(", ")}) and pushing ${routeInfos.map((e) => e.routeName).join(", ")}");
// OPTION A: This does not work
await pushAndPopUntil(routeInfos.first, predicate: (_) => false); // This never finishes the future
if (routeInfos.length > 1) await pushAll(routeInfos.skip(1).toList());
// OPTION B: This does not work either
// for(int i = 0; i < routesInStack.length; i++) {
// popForced(); // This does not seem to pop the root route, it is duplicated in the stack after the pushAll
// }
// await pushAll(routeInfos);
Debug.log("Result of popAllAndPushAll: ${stack.map((e) => e.routeData.name).join(", ")}");
}
}
from auto_route_library.
More information that might be relevant:
I do have the AuthGuard that looks like this:
class AuthGuard extends AutoRouteGuard {
@override
void onNavigation(NavigationResolver resolver, StackRouter router) {
bool userIsLogged = AuthServiceV2().isLoggedIn;
if (userIsLogged) {
resolver.next(true);
} else {
resolver.redirect(const AuthRoute());
AuthServiceV2().loginResultCallback = (bool didLogin) async => resolver.next(didLogin);
}
}
}
And then in my setUserId
(which is my equivalent to "login/logout" handling, I do the following:
Future<void> setUserId(String? newUser) async {
_userId = newUser;
if (newUser != null) {
await loginResultCallback?.call(true);
loginResultCallback = null;
// Recreate all routes, Expect to have "redirected route" by the AuthGuard to be already replaced by the loginResultCallback. All the stack should be rebuilt (including the root)
await AppRouter().rebuildAll();
} else {
// Reroute, Expected to have the full stack rebuilt (including root) and setting "HomeRoute" as the root.
if (AppRouter().stack.isNotEmpty) await AppRouter().popAllAndPushAll([const HomeRoute()]);
}
}
from auto_route_library.
My SOLUTION
I've ended up with a solution which, even though it is not 100% ideal, it gets you 90% of the way (I am only missing that I don't feel completely safe using it).
I removed the "futures" from the equation and since I detected that I can not reliably await for them, and added Post Frame Callbacks to execute the stuff that should be executed afterwards.
These are my final methods to rebuildAll
and popAllAndPushAll
:
void rebuildAll() {
List<RouteData> routesDataList = stack.map((e) => e.routeData).toList();
List<PageRouteInfo<dynamic>> routeInfos = routesDataList.map((routeData) => PageRouteInfo.fromMatch(routeData.topMatch)).toList();
if (routeInfos.isNotEmpty) {
popAllAndPushAll(routeInfos);
}
}
void popAllAndPushAll(List<PageRouteInfo<dynamic>> routeInfos) {
List<RouteData> routesInStack = stack.map((e) => e.routeData).toList();
/*await*/ pushAndPopUntil(routeInfos.first, predicate: (_) => false); // This never finishes the future. ISSUE: https://github.com/Milad-Akarie/auto_route_library/issues/1964
if (routeInfos.length > 1) WidgetsBinding.instance.addPostFrameCallback((_) => pushAll(routeInfos.skip(1).toList()));
}
And my AuthService now is managed like this:
Future<void> setUserId(String? newUser) async {
_userId = newUser;
if (newUser != null) {
await loginResultCallback?.call(true);
loginResultCallback = null;
WidgetsBinding.instance.addPostFrameCallback((_) async => AppRouter().rebuildAll());
} else {
if (AppRouter().stack.isNotEmpty) AppRouter().popAllAndPushAll([const HomeRoute()]);
}
}
This works, but it seems odd. At least, I believe there is an issue with the future of the pushAndPopUntil
since if I await for it to finish, the next instruction is not executed.
from auto_route_library.
Related Issues (20)
- Handling of back navigation in nested routes, ignored PopScope HOT 2
- pushing to same screen issue
- New Xcode error out of the blue HOT 1
- [Bug] - Using the same Screen as Two routes results into an exception
- [QUESTION] Why RouteMatch operator == doesn't have args?
- AutoTabsRouter.pageView sibling views defaults to path '' HOT 2
- Cannot navigate to child route with @PathParam.inherit("param"). HOT 12
- deepLinkBuilder && doubling element's tree HOT 1
- Pushing to sub-page in another tab and maintaining history? HOT 5
- deepLinkBuilder Not working on Production HOT 1
- Default function argument value has no import prefix
- Automatically back when use CustomRoute with swipe for back HOT 1
- Unable to Set Custom Transition Duration While Maintaining iOS Swipe Back Gesture HOT 2
- browser buttons navigation in flutter web HOT 1
- Got an error when navigation back web button with nested route HOT 5
- PopScope, Function(bool)? onPopInvoked, boolean value is always true for web even when canPop is false
- Route get reset after keyboard appears HOT 1
- Bad state: Future already completed HOT 2
- Blank screen when first opening the app HOT 3
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.