nav.dart 22 KB

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