nav.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_spinkit/flutter_spinkit.dart';
  4. import 'package:go_router/go_router.dart';
  5. import 'package:page_transition/page_transition.dart';
  6. import 'package:provider/provider.dart';
  7. import '/backend/schema/structs/index.dart';
  8. import '/auth/custom_auth/custom_auth_user_provider.dart';
  9. import '/main.dart';
  10. import '/flutter_flow/flutter_flow_theme.dart';
  11. import '/flutter_flow/lat_lng.dart';
  12. import '/flutter_flow/place.dart';
  13. import '/flutter_flow/flutter_flow_util.dart';
  14. import 'serialization_util.dart';
  15. import '/index.dart';
  16. export 'package:go_router/go_router.dart';
  17. export 'serialization_util.dart';
  18. const kTransitionInfoKey = '__transition_info__';
  19. GlobalKey<NavigatorState> appNavigatorKey = GlobalKey<NavigatorState>();
  20. const debugRouteLinkMap = {
  21. '/login':
  22. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=login',
  23. '/horecagelegenheidCurrent':
  24. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=horecagelegenheidCurrent',
  25. '/home':
  26. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=home',
  27. '/selectprovinciegemeente':
  28. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=selectprovinciegemeente',
  29. '/pUitgaanPage':
  30. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=PUitgaanPage',
  31. '/event':
  32. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=Event',
  33. '/eventCurrent':
  34. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=EventCurrent',
  35. '/kanwegHorecagelegenhedenOverzicht':
  36. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHorecagelegenhedenOverzicht',
  37. '/horecagelegenhedenOverzichtProvinciePage':
  38. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=HorecagelegenhedenOverzichtProvinciePage',
  39. '/kanwegHorecagelegenhedenOverzichtSortPage':
  40. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHorecagelegenhedenOverzichtSortPage',
  41. '/wachtwoordVergeten':
  42. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=wachtwoordVergeten',
  43. '/favorieten':
  44. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=favorieten',
  45. '/kanweg':
  46. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweg',
  47. '/favorietenCopy':
  48. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=favorietenCopy',
  49. '/kanwegTestUpload':
  50. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegTestUpload',
  51. '/mijnProfiel':
  52. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=mijnProfiel',
  53. '/stadsactiviteitAanmaken':
  54. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=stadsactiviteitAanmaken',
  55. '/horecagelegenhedenOverzichtCopy':
  56. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=HorecagelegenhedenOverzichtCopy',
  57. '/horecagelegenhedenOverzichtCopy2':
  58. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=HorecagelegenhedenOverzichtCopy2',
  59. '/horecagelegenhedenOverzichtCopy2Copy':
  60. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=HorecagelegenhedenOverzichtCopy2Copy',
  61. '/kanwegHomeCopy':
  62. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHomeCopy',
  63. '/uitgaansevenementAanmaken':
  64. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=uitgaansevenementAanmaken',
  65. '/kanweghorecagelegenheidCurrentCopy':
  66. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweghorecagelegenheidCurrentCopy',
  67. '/horecagelegenhedenOverzichtCurrent':
  68. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=horecagelegenhedenOverzichtCurrent',
  69. '/kanwegHorecagelegenhedenOverzichtCopy3Copy':
  70. 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHorecagelegenhedenOverzichtCopy3Copy'
  71. };
  72. class AppStateNotifier extends ChangeNotifier {
  73. AppStateNotifier._();
  74. static AppStateNotifier? _instance;
  75. static AppStateNotifier get instance => _instance ??= AppStateNotifier._();
  76. UitgaanskrantAuthUser? initialUser;
  77. UitgaanskrantAuthUser? user;
  78. bool showSplashImage = true;
  79. String? _redirectLocation;
  80. /// Determines whether the app will refresh and build again when a sign
  81. /// in or sign out happens. This is useful when the app is launched or
  82. /// on an unexpected logout. However, this must be turned off when we
  83. /// intend to sign in/out and then navigate or perform any actions after.
  84. /// Otherwise, this will trigger a refresh and interrupt the action(s).
  85. bool notifyOnAuthChange = true;
  86. bool get loading => user == null || showSplashImage;
  87. bool get loggedIn => user?.loggedIn ?? false;
  88. bool get initiallyLoggedIn => initialUser?.loggedIn ?? false;
  89. bool get shouldRedirect => loggedIn && _redirectLocation != null;
  90. String getRedirectLocation() => _redirectLocation!;
  91. bool hasRedirect() => _redirectLocation != null;
  92. void setRedirectLocationIfUnset(String loc) => _redirectLocation ??= loc;
  93. void clearRedirectLocation() => _redirectLocation = null;
  94. /// Mark as not needing to notify on a sign in / out when we intend
  95. /// to perform subsequent actions (such as navigation) afterwards.
  96. void updateNotifyOnAuthChange(bool notify) => notifyOnAuthChange = notify;
  97. void update(UitgaanskrantAuthUser newUser) {
  98. final shouldUpdate =
  99. user?.uid == null || newUser.uid == null || user?.uid != newUser.uid;
  100. initialUser ??= newUser;
  101. user = newUser;
  102. // Refresh the app on auth change unless explicitly marked otherwise.
  103. // No need to update unless the user has changed.
  104. if (notifyOnAuthChange && shouldUpdate) {
  105. notifyListeners();
  106. }
  107. // Once again mark the notifier as needing to update on auth change
  108. // (in order to catch sign in / out events).
  109. updateNotifyOnAuthChange(true);
  110. }
  111. void stopShowingSplashImage() {
  112. showSplashImage = false;
  113. notifyListeners();
  114. }
  115. }
  116. GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter(
  117. initialLocation: '/',
  118. debugLogDiagnostics: true,
  119. refreshListenable: appStateNotifier,
  120. navigatorKey: appNavigatorKey,
  121. errorBuilder: (context, state) =>
  122. appStateNotifier.loggedIn ? HomeWidget() : HomeWidget(),
  123. routes: [
  124. FFRoute(
  125. name: '_initialize',
  126. path: '/',
  127. builder: (context, _) =>
  128. appStateNotifier.loggedIn ? HomeWidget() : HomeWidget(),
  129. ),
  130. FFRoute(
  131. name: LoginWidget.routeName,
  132. path: LoginWidget.routePath,
  133. builder: (context, params) => LoginWidget(),
  134. ),
  135. FFRoute(
  136. name: HorecagelegenheidCurrentWidget.routeName,
  137. path: HorecagelegenheidCurrentWidget.routePath,
  138. builder: (context, params) => HorecagelegenheidCurrentWidget(
  139. nid: params.getParam(
  140. 'nid',
  141. ParamType.String,
  142. ),
  143. ),
  144. ),
  145. FFRoute(
  146. name: HomeWidget.routeName,
  147. path: HomeWidget.routePath,
  148. builder: (context, params) => HomeWidget(),
  149. ),
  150. FFRoute(
  151. name: SelectprovinciegemeenteWidget.routeName,
  152. path: SelectprovinciegemeenteWidget.routePath,
  153. builder: (context, params) => SelectprovinciegemeenteWidget(),
  154. ),
  155. FFRoute(
  156. name: PUitgaanPageWidget.routeName,
  157. path: PUitgaanPageWidget.routePath,
  158. builder: (context, params) => PUitgaanPageWidget(
  159. plaats: params.getParam(
  160. 'plaats',
  161. ParamType.String,
  162. ),
  163. services: params.getParam(
  164. 'services',
  165. ParamType.String,
  166. ),
  167. ),
  168. ),
  169. FFRoute(
  170. name: EventWidget.routeName,
  171. path: EventWidget.routePath,
  172. builder: (context, params) => EventWidget(
  173. nid: params.getParam(
  174. 'nid',
  175. ParamType.String,
  176. ),
  177. ),
  178. ),
  179. FFRoute(
  180. name: EventCurrentWidget.routeName,
  181. path: EventCurrentWidget.routePath,
  182. builder: (context, params) => EventCurrentWidget(
  183. nid: params.getParam(
  184. 'nid',
  185. ParamType.String,
  186. ),
  187. horecaid: params.getParam(
  188. 'horecaid',
  189. ParamType.String,
  190. ),
  191. ),
  192. ),
  193. FFRoute(
  194. name: KanwegHorecagelegenhedenOverzichtWidget.routeName,
  195. path: KanwegHorecagelegenhedenOverzichtWidget.routePath,
  196. builder: (context, params) => KanwegHorecagelegenhedenOverzichtWidget(
  197. plaats: params.getParam(
  198. 'plaats',
  199. ParamType.String,
  200. ),
  201. ),
  202. ),
  203. FFRoute(
  204. name: HorecagelegenhedenOverzichtProvinciePageWidget.routeName,
  205. path: HorecagelegenhedenOverzichtProvinciePageWidget.routePath,
  206. builder: (context, params) =>
  207. HorecagelegenhedenOverzichtProvinciePageWidget(
  208. plaats: params.getParam(
  209. 'plaats',
  210. ParamType.String,
  211. ),
  212. ),
  213. ),
  214. FFRoute(
  215. name: KanwegHorecagelegenhedenOverzichtSortPageWidget.routeName,
  216. path: KanwegHorecagelegenhedenOverzichtSortPageWidget.routePath,
  217. builder: (context, params) =>
  218. KanwegHorecagelegenhedenOverzichtSortPageWidget(
  219. plaats: params.getParam(
  220. 'plaats',
  221. ParamType.String,
  222. ),
  223. ),
  224. ),
  225. FFRoute(
  226. name: WachtwoordVergetenWidget.routeName,
  227. path: WachtwoordVergetenWidget.routePath,
  228. builder: (context, params) => WachtwoordVergetenWidget(),
  229. ),
  230. FFRoute(
  231. name: FavorietenWidget.routeName,
  232. path: FavorietenWidget.routePath,
  233. builder: (context, params) => FavorietenWidget(),
  234. ),
  235. FFRoute(
  236. name: KanwegWidget.routeName,
  237. path: KanwegWidget.routePath,
  238. builder: (context, params) => KanwegWidget(),
  239. ),
  240. FFRoute(
  241. name: FavorietenCopyWidget.routeName,
  242. path: FavorietenCopyWidget.routePath,
  243. builder: (context, params) => FavorietenCopyWidget(),
  244. ),
  245. FFRoute(
  246. name: KanwegTestUploadWidget.routeName,
  247. path: KanwegTestUploadWidget.routePath,
  248. builder: (context, params) => KanwegTestUploadWidget(),
  249. ),
  250. FFRoute(
  251. name: MijnProfielWidget.routeName,
  252. path: MijnProfielWidget.routePath,
  253. builder: (context, params) => MijnProfielWidget(),
  254. ),
  255. FFRoute(
  256. name: StadsactiviteitAanmakenWidget.routeName,
  257. path: StadsactiviteitAanmakenWidget.routePath,
  258. builder: (context, params) => StadsactiviteitAanmakenWidget(),
  259. ),
  260. FFRoute(
  261. name: HorecagelegenhedenOverzichtCopyWidget.routeName,
  262. path: HorecagelegenhedenOverzichtCopyWidget.routePath,
  263. builder: (context, params) => HorecagelegenhedenOverzichtCopyWidget(
  264. plaats: params.getParam(
  265. 'plaats',
  266. ParamType.String,
  267. ),
  268. ),
  269. ),
  270. FFRoute(
  271. name: HorecagelegenhedenOverzichtCopy2Widget.routeName,
  272. path: HorecagelegenhedenOverzichtCopy2Widget.routePath,
  273. builder: (context, params) => HorecagelegenhedenOverzichtCopy2Widget(
  274. plaats: params.getParam(
  275. 'plaats',
  276. ParamType.String,
  277. ),
  278. ),
  279. ),
  280. FFRoute(
  281. name: HorecagelegenhedenOverzichtCopy2CopyWidget.routeName,
  282. path: HorecagelegenhedenOverzichtCopy2CopyWidget.routePath,
  283. builder: (context, params) =>
  284. HorecagelegenhedenOverzichtCopy2CopyWidget(
  285. plaats: params.getParam(
  286. 'plaats',
  287. ParamType.String,
  288. ),
  289. ),
  290. ),
  291. FFRoute(
  292. name: KanwegHomeCopyWidget.routeName,
  293. path: KanwegHomeCopyWidget.routePath,
  294. builder: (context, params) => KanwegHomeCopyWidget(),
  295. ),
  296. FFRoute(
  297. name: UitgaansevenementAanmakenWidget.routeName,
  298. path: UitgaansevenementAanmakenWidget.routePath,
  299. builder: (context, params) => UitgaansevenementAanmakenWidget(
  300. horecagelegenheidNid: params.getParam(
  301. 'horecagelegenheidNid',
  302. ParamType.String,
  303. ),
  304. ),
  305. ),
  306. FFRoute(
  307. name: KanweghorecagelegenheidCurrentCopyWidget.routeName,
  308. path: KanweghorecagelegenheidCurrentCopyWidget.routePath,
  309. builder: (context, params) =>
  310. KanweghorecagelegenheidCurrentCopyWidget(
  311. nid: params.getParam(
  312. 'nid',
  313. ParamType.String,
  314. ),
  315. ),
  316. ),
  317. FFRoute(
  318. name: HorecagelegenhedenOverzichtCurrentWidget.routeName,
  319. path: HorecagelegenhedenOverzichtCurrentWidget.routePath,
  320. builder: (context, params) =>
  321. HorecagelegenhedenOverzichtCurrentWidget(
  322. plaats: params.getParam(
  323. 'plaats',
  324. ParamType.String,
  325. ),
  326. ),
  327. ),
  328. FFRoute(
  329. name: KanwegHorecagelegenhedenOverzichtCopy3CopyWidget.routeName,
  330. path: KanwegHorecagelegenhedenOverzichtCopy3CopyWidget.routePath,
  331. builder: (context, params) =>
  332. KanwegHorecagelegenhedenOverzichtCopy3CopyWidget(
  333. plaats: params.getParam(
  334. 'plaats',
  335. ParamType.String,
  336. ),
  337. ),
  338. )
  339. ].map((r) => r.toRoute(appStateNotifier)).toList(),
  340. observers: ffNavigatorObservers,
  341. );
  342. extension NavParamExtensions on Map<String, String?> {
  343. Map<String, String> get withoutNulls => Map.fromEntries(
  344. entries
  345. .where((e) => e.value != null)
  346. .map((e) => MapEntry(e.key, e.value!)),
  347. );
  348. }
  349. extension NavigationExtensions on BuildContext {
  350. void goNamedAuth(
  351. String name,
  352. bool mounted, {
  353. Map<String, String> pathParameters = const <String, String>{},
  354. Map<String, String> queryParameters = const <String, String>{},
  355. Object? extra,
  356. bool ignoreRedirect = false,
  357. }) =>
  358. !mounted || GoRouter.of(this).shouldRedirect(ignoreRedirect)
  359. ? null
  360. : goNamed(
  361. name,
  362. pathParameters: pathParameters,
  363. queryParameters: queryParameters,
  364. extra: extra,
  365. );
  366. void pushNamedAuth(
  367. String name,
  368. bool mounted, {
  369. Map<String, String> pathParameters = const <String, String>{},
  370. Map<String, String> queryParameters = const <String, String>{},
  371. Object? extra,
  372. bool ignoreRedirect = false,
  373. }) =>
  374. !mounted || GoRouter.of(this).shouldRedirect(ignoreRedirect)
  375. ? null
  376. : pushNamed(
  377. name,
  378. pathParameters: pathParameters,
  379. queryParameters: queryParameters,
  380. extra: extra,
  381. );
  382. void safePop() {
  383. // If there is only one route on the stack, navigate to the initial
  384. // page instead of popping.
  385. if (canPop()) {
  386. pop();
  387. } else {
  388. go('/');
  389. }
  390. }
  391. }
  392. extension GoRouterExtensions on GoRouter {
  393. AppStateNotifier get appState => AppStateNotifier.instance;
  394. void prepareAuthEvent([bool ignoreRedirect = false]) =>
  395. appState.hasRedirect() && !ignoreRedirect
  396. ? null
  397. : appState.updateNotifyOnAuthChange(false);
  398. bool shouldRedirect(bool ignoreRedirect) =>
  399. !ignoreRedirect && appState.hasRedirect();
  400. void clearRedirectLocation() => appState.clearRedirectLocation();
  401. void setRedirectLocationIfUnset(String location) =>
  402. appState.updateNotifyOnAuthChange(false);
  403. }
  404. extension _GoRouterStateExtensions on GoRouterState {
  405. Map<String, dynamic> get extraMap =>
  406. extra != null ? extra as Map<String, dynamic> : {};
  407. Map<String, dynamic> get allParams => <String, dynamic>{}
  408. ..addAll(pathParameters)
  409. ..addAll(uri.queryParameters)
  410. ..addAll(extraMap);
  411. TransitionInfo get transitionInfo => extraMap.containsKey(kTransitionInfoKey)
  412. ? extraMap[kTransitionInfoKey] as TransitionInfo
  413. : TransitionInfo.appDefault();
  414. }
  415. class FFParameters {
  416. FFParameters(this.state, [this.asyncParams = const {}]);
  417. final GoRouterState state;
  418. final Map<String, Future<dynamic> Function(String)> asyncParams;
  419. Map<String, dynamic> futureParamValues = {};
  420. // Parameters are empty if the params map is empty or if the only parameter
  421. // present is the special extra parameter reserved for the transition info.
  422. bool get isEmpty =>
  423. state.allParams.isEmpty ||
  424. (state.allParams.length == 1 &&
  425. state.extraMap.containsKey(kTransitionInfoKey));
  426. bool isAsyncParam(MapEntry<String, dynamic> param) =>
  427. asyncParams.containsKey(param.key) && param.value is String;
  428. bool get hasFutures => state.allParams.entries.any(isAsyncParam);
  429. Future<bool> completeFutures() => Future.wait(
  430. state.allParams.entries.where(isAsyncParam).map(
  431. (param) async {
  432. final doc = await asyncParams[param.key]!(param.value)
  433. .onError((_, __) => null);
  434. if (doc != null) {
  435. futureParamValues[param.key] = doc;
  436. return true;
  437. }
  438. return false;
  439. },
  440. ),
  441. ).onError((_, __) => [false]).then((v) => v.every((e) => e));
  442. dynamic getParam<T>(
  443. String paramName,
  444. ParamType type, {
  445. bool isList = false,
  446. StructBuilder<T>? structBuilder,
  447. }) {
  448. if (futureParamValues.containsKey(paramName)) {
  449. return futureParamValues[paramName];
  450. }
  451. if (!state.allParams.containsKey(paramName)) {
  452. return null;
  453. }
  454. final param = state.allParams[paramName];
  455. // Got parameter from `extras`, so just directly return it.
  456. if (param is! String) {
  457. return param;
  458. }
  459. // Return serialized value.
  460. return deserializeParam<T>(
  461. param,
  462. type,
  463. isList,
  464. structBuilder: structBuilder,
  465. );
  466. }
  467. }
  468. class FFRoute {
  469. const FFRoute({
  470. required this.name,
  471. required this.path,
  472. required this.builder,
  473. this.requireAuth = false,
  474. this.asyncParams = const {},
  475. this.routes = const [],
  476. });
  477. final String name;
  478. final String path;
  479. final bool requireAuth;
  480. final Map<String, Future<dynamic> Function(String)> asyncParams;
  481. final Widget Function(BuildContext, FFParameters) builder;
  482. final List<GoRoute> routes;
  483. GoRoute toRoute(AppStateNotifier appStateNotifier) => GoRoute(
  484. name: name,
  485. path: path,
  486. redirect: (context, state) {
  487. if (appStateNotifier.shouldRedirect) {
  488. final redirectLocation = appStateNotifier.getRedirectLocation();
  489. appStateNotifier.clearRedirectLocation();
  490. return redirectLocation;
  491. }
  492. if (requireAuth && !appStateNotifier.loggedIn) {
  493. appStateNotifier.setRedirectLocationIfUnset(state.uri.toString());
  494. return '/home';
  495. }
  496. return null;
  497. },
  498. pageBuilder: (context, state) {
  499. fixStatusBarOniOS16AndBelow(context);
  500. final ffParams = FFParameters(state, asyncParams);
  501. final page = ffParams.hasFutures
  502. ? FutureBuilder(
  503. future: ffParams.completeFutures(),
  504. builder: (context, _) => builder(context, ffParams),
  505. )
  506. : builder(context, ffParams);
  507. final child = appStateNotifier.loading
  508. ? Center(
  509. child: SizedBox(
  510. width: 80.0,
  511. height: 80.0,
  512. child: SpinKitFadingCircle(
  513. color: FlutterFlowTheme.of(context).primary,
  514. size: 80.0,
  515. ),
  516. ),
  517. )
  518. : page;
  519. final transitionInfo = state.transitionInfo;
  520. return transitionInfo.hasTransition
  521. ? CustomTransitionPage(
  522. key: state.pageKey,
  523. name: state.name,
  524. child: child,
  525. transitionDuration: transitionInfo.duration,
  526. transitionsBuilder:
  527. (context, animation, secondaryAnimation, child) =>
  528. PageTransition(
  529. type: transitionInfo.transitionType,
  530. duration: transitionInfo.duration,
  531. reverseDuration: transitionInfo.duration,
  532. alignment: transitionInfo.alignment,
  533. child: child,
  534. ).buildTransitions(
  535. context,
  536. animation,
  537. secondaryAnimation,
  538. child,
  539. ),
  540. )
  541. : MaterialPage(
  542. key: state.pageKey, name: state.name, child: child);
  543. },
  544. routes: routes,
  545. );
  546. }
  547. class TransitionInfo {
  548. const TransitionInfo({
  549. required this.hasTransition,
  550. this.transitionType = PageTransitionType.fade,
  551. this.duration = const Duration(milliseconds: 300),
  552. this.alignment,
  553. });
  554. final bool hasTransition;
  555. final PageTransitionType transitionType;
  556. final Duration duration;
  557. final Alignment? alignment;
  558. static TransitionInfo appDefault() => TransitionInfo(hasTransition: false);
  559. }
  560. class RootPageContext {
  561. const RootPageContext(this.isRootPage, [this.errorRoute]);
  562. final bool isRootPage;
  563. final String? errorRoute;
  564. static bool isInactiveRootPage(BuildContext context) {
  565. final rootPageContext = context.read<RootPageContext?>();
  566. final isRootPage = rootPageContext?.isRootPage ?? false;
  567. final location = GoRouterState.of(context).uri.toString();
  568. return isRootPage &&
  569. location != '/' &&
  570. location != rootPageContext?.errorRoute;
  571. }
  572. static Widget wrap(Widget child, {String? errorRoute}) => Provider.value(
  573. value: RootPageContext(true, errorRoute),
  574. child: child,
  575. );
  576. }
  577. extension GoRouterLocationExtension on GoRouter {
  578. String getCurrentLocation() {
  579. final RouteMatch lastMatch = routerDelegate.currentConfiguration.last;
  580. final RouteMatchList matchList = lastMatch is ImperativeRouteMatch
  581. ? lastMatch.matches
  582. : routerDelegate.currentConfiguration;
  583. return matchList.uri.toString();
  584. }
  585. }