import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:go_router/go_router.dart'; import 'package:page_transition/page_transition.dart'; import 'package:provider/provider.dart'; import '/backend/schema/structs/index.dart'; import '/auth/custom_auth/custom_auth_user_provider.dart'; import '/main.dart'; import '/flutter_flow/flutter_flow_theme.dart'; import '/flutter_flow/lat_lng.dart'; import '/flutter_flow/place.dart'; import '/flutter_flow/flutter_flow_util.dart'; import 'serialization_util.dart'; import '/index.dart'; export 'package:go_router/go_router.dart'; export 'serialization_util.dart'; const kTransitionInfoKey = '__transition_info__'; GlobalKey appNavigatorKey = GlobalKey(); const debugRouteLinkMap = { '/login': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=login', '/horecagelegenheidCurrent': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=horecagelegenheidCurrent', '/home': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=home', '/selectprovinciegemeente': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=selectprovinciegemeente', '/pUitgaanPage': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=PUitgaanPage', '/event': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=Event', '/eventCurrent': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=EventCurrent', '/kanwegHorecagelegenhedenOverzicht': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHorecagelegenhedenOverzicht', '/horecagelegenhedenOverzichtProvinciePage': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=HorecagelegenhedenOverzichtProvinciePage', '/kanwegHorecagelegenhedenOverzichtSortPage': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHorecagelegenhedenOverzichtSortPage', '/wachtwoordVergeten': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=wachtwoordVergeten', '/favorieten': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=favorieten', '/kanweg': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweg', '/favorietenCopy': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=favorietenCopy', '/kanwegTestUpload': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegTestUpload', '/mijnProfiel': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=mijnProfiel', '/stadsactiviteitAanmaken': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=stadsactiviteitAanmaken', '/kanwegHomeCopy': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHomeCopy', '/uitgaansevenementAanmaken': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=uitgaansevenementAanmaken', '/kanweghorecagelegenheidCurrentCopy': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanweghorecagelegenheidCurrentCopy', '/horecagelegenhedenOverzichtCurrent': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=horecagelegenhedenOverzichtCurrent', '/kanwegHorecagelegenhedenOverzichtCopy3Copy': 'https://app.flutterflow.io/project/uitgaanskrant-1qhvtd?tab=uiBuilder&page=kanwegHorecagelegenhedenOverzichtCopy3Copy' }; class AppStateNotifier extends ChangeNotifier { AppStateNotifier._(); static AppStateNotifier? _instance; static AppStateNotifier get instance => _instance ??= AppStateNotifier._(); UitgaanskrantAuthUser? initialUser; UitgaanskrantAuthUser? user; bool showSplashImage = true; String? _redirectLocation; /// Determines whether the app will refresh and build again when a sign /// in or sign out happens. This is useful when the app is launched or /// on an unexpected logout. However, this must be turned off when we /// intend to sign in/out and then navigate or perform any actions after. /// Otherwise, this will trigger a refresh and interrupt the action(s). bool notifyOnAuthChange = true; bool get loading => user == null || showSplashImage; bool get loggedIn => user?.loggedIn ?? false; bool get initiallyLoggedIn => initialUser?.loggedIn ?? false; bool get shouldRedirect => loggedIn && _redirectLocation != null; String getRedirectLocation() => _redirectLocation!; bool hasRedirect() => _redirectLocation != null; void setRedirectLocationIfUnset(String loc) => _redirectLocation ??= loc; void clearRedirectLocation() => _redirectLocation = null; /// Mark as not needing to notify on a sign in / out when we intend /// to perform subsequent actions (such as navigation) afterwards. void updateNotifyOnAuthChange(bool notify) => notifyOnAuthChange = notify; void update(UitgaanskrantAuthUser newUser) { final shouldUpdate = user?.uid == null || newUser.uid == null || user?.uid != newUser.uid; initialUser ??= newUser; user = newUser; // Refresh the app on auth change unless explicitly marked otherwise. // No need to update unless the user has changed. if (notifyOnAuthChange && shouldUpdate) { notifyListeners(); } // Once again mark the notifier as needing to update on auth change // (in order to catch sign in / out events). updateNotifyOnAuthChange(true); } void stopShowingSplashImage() { showSplashImage = false; notifyListeners(); } } GoRouter createRouter(AppStateNotifier appStateNotifier) => GoRouter( initialLocation: '/', debugLogDiagnostics: true, refreshListenable: appStateNotifier, navigatorKey: appNavigatorKey, errorBuilder: (context, state) => appStateNotifier.loggedIn ? HomeWidget() : HomeWidget(), routes: [ FFRoute( name: '_initialize', path: '/', builder: (context, _) => appStateNotifier.loggedIn ? HomeWidget() : HomeWidget(), ), FFRoute( name: LoginWidget.routeName, path: LoginWidget.routePath, builder: (context, params) => LoginWidget(), ), FFRoute( name: HorecagelegenheidCurrentWidget.routeName, path: HorecagelegenheidCurrentWidget.routePath, builder: (context, params) => HorecagelegenheidCurrentWidget( nid: params.getParam( 'nid', ParamType.String, ), ), ), FFRoute( name: HomeWidget.routeName, path: HomeWidget.routePath, builder: (context, params) => HomeWidget(), ), FFRoute( name: SelectprovinciegemeenteWidget.routeName, path: SelectprovinciegemeenteWidget.routePath, builder: (context, params) => SelectprovinciegemeenteWidget(), ), FFRoute( name: PUitgaanPageWidget.routeName, path: PUitgaanPageWidget.routePath, builder: (context, params) => PUitgaanPageWidget( plaats: params.getParam( 'plaats', ParamType.String, ), services: params.getParam( 'services', ParamType.String, ), ), ), FFRoute( name: EventWidget.routeName, path: EventWidget.routePath, builder: (context, params) => EventWidget( nid: params.getParam( 'nid', ParamType.String, ), ), ), FFRoute( name: EventCurrentWidget.routeName, path: EventCurrentWidget.routePath, builder: (context, params) => EventCurrentWidget( nid: params.getParam( 'nid', ParamType.String, ), horecaid: params.getParam( 'horecaid', ParamType.String, ), ), ), FFRoute( name: KanwegHorecagelegenhedenOverzichtWidget.routeName, path: KanwegHorecagelegenhedenOverzichtWidget.routePath, builder: (context, params) => KanwegHorecagelegenhedenOverzichtWidget( plaats: params.getParam( 'plaats', ParamType.String, ), ), ), FFRoute( name: HorecagelegenhedenOverzichtProvinciePageWidget.routeName, path: HorecagelegenhedenOverzichtProvinciePageWidget.routePath, builder: (context, params) => HorecagelegenhedenOverzichtProvinciePageWidget( plaats: params.getParam( 'plaats', ParamType.String, ), ), ), FFRoute( name: KanwegHorecagelegenhedenOverzichtSortPageWidget.routeName, path: KanwegHorecagelegenhedenOverzichtSortPageWidget.routePath, builder: (context, params) => KanwegHorecagelegenhedenOverzichtSortPageWidget( plaats: params.getParam( 'plaats', ParamType.String, ), ), ), FFRoute( name: WachtwoordVergetenWidget.routeName, path: WachtwoordVergetenWidget.routePath, builder: (context, params) => WachtwoordVergetenWidget(), ), FFRoute( name: FavorietenWidget.routeName, path: FavorietenWidget.routePath, builder: (context, params) => FavorietenWidget(), ), FFRoute( name: KanwegWidget.routeName, path: KanwegWidget.routePath, builder: (context, params) => KanwegWidget(), ), FFRoute( name: FavorietenCopyWidget.routeName, path: FavorietenCopyWidget.routePath, builder: (context, params) => FavorietenCopyWidget(), ), FFRoute( name: KanwegTestUploadWidget.routeName, path: KanwegTestUploadWidget.routePath, builder: (context, params) => KanwegTestUploadWidget(), ), FFRoute( name: MijnProfielWidget.routeName, path: MijnProfielWidget.routePath, builder: (context, params) => MijnProfielWidget(), ), FFRoute( name: StadsactiviteitAanmakenWidget.routeName, path: StadsactiviteitAanmakenWidget.routePath, builder: (context, params) => StadsactiviteitAanmakenWidget(), ), FFRoute( name: KanwegHomeCopyWidget.routeName, path: KanwegHomeCopyWidget.routePath, builder: (context, params) => KanwegHomeCopyWidget(), ), FFRoute( name: UitgaansevenementAanmakenWidget.routeName, path: UitgaansevenementAanmakenWidget.routePath, builder: (context, params) => UitgaansevenementAanmakenWidget( horecagelegenheidNid: params.getParam( 'horecagelegenheidNid', ParamType.String, ), ), ), FFRoute( name: KanweghorecagelegenheidCurrentCopyWidget.routeName, path: KanweghorecagelegenheidCurrentCopyWidget.routePath, builder: (context, params) => KanweghorecagelegenheidCurrentCopyWidget( nid: params.getParam( 'nid', ParamType.String, ), ), ), FFRoute( name: HorecagelegenhedenOverzichtCurrentWidget.routeName, path: HorecagelegenhedenOverzichtCurrentWidget.routePath, builder: (context, params) => HorecagelegenhedenOverzichtCurrentWidget( plaats: params.getParam( 'plaats', ParamType.String, ), ), ), FFRoute( name: KanwegHorecagelegenhedenOverzichtCopy3CopyWidget.routeName, path: KanwegHorecagelegenhedenOverzichtCopy3CopyWidget.routePath, builder: (context, params) => KanwegHorecagelegenhedenOverzichtCopy3CopyWidget( plaats: params.getParam( 'plaats', ParamType.String, ), ), ) ].map((r) => r.toRoute(appStateNotifier)).toList(), observers: ffNavigatorObservers, ); extension NavParamExtensions on Map { Map get withoutNulls => Map.fromEntries( entries .where((e) => e.value != null) .map((e) => MapEntry(e.key, e.value!)), ); } extension NavigationExtensions on BuildContext { void goNamedAuth( String name, bool mounted, { Map pathParameters = const {}, Map queryParameters = const {}, Object? extra, bool ignoreRedirect = false, }) => !mounted || GoRouter.of(this).shouldRedirect(ignoreRedirect) ? null : goNamed( name, pathParameters: pathParameters, queryParameters: queryParameters, extra: extra, ); void pushNamedAuth( String name, bool mounted, { Map pathParameters = const {}, Map queryParameters = const {}, Object? extra, bool ignoreRedirect = false, }) => !mounted || GoRouter.of(this).shouldRedirect(ignoreRedirect) ? null : pushNamed( name, pathParameters: pathParameters, queryParameters: queryParameters, extra: extra, ); void safePop() { // If there is only one route on the stack, navigate to the initial // page instead of popping. if (canPop()) { pop(); } else { go('/'); } } } extension GoRouterExtensions on GoRouter { AppStateNotifier get appState => AppStateNotifier.instance; void prepareAuthEvent([bool ignoreRedirect = false]) => appState.hasRedirect() && !ignoreRedirect ? null : appState.updateNotifyOnAuthChange(false); bool shouldRedirect(bool ignoreRedirect) => !ignoreRedirect && appState.hasRedirect(); void clearRedirectLocation() => appState.clearRedirectLocation(); void setRedirectLocationIfUnset(String location) => appState.updateNotifyOnAuthChange(false); } extension _GoRouterStateExtensions on GoRouterState { Map get extraMap => extra != null ? extra as Map : {}; Map get allParams => {} ..addAll(pathParameters) ..addAll(uri.queryParameters) ..addAll(extraMap); TransitionInfo get transitionInfo => extraMap.containsKey(kTransitionInfoKey) ? extraMap[kTransitionInfoKey] as TransitionInfo : TransitionInfo.appDefault(); } class FFParameters { FFParameters(this.state, [this.asyncParams = const {}]); final GoRouterState state; final Map Function(String)> asyncParams; Map futureParamValues = {}; // Parameters are empty if the params map is empty or if the only parameter // present is the special extra parameter reserved for the transition info. bool get isEmpty => state.allParams.isEmpty || (state.allParams.length == 1 && state.extraMap.containsKey(kTransitionInfoKey)); bool isAsyncParam(MapEntry param) => asyncParams.containsKey(param.key) && param.value is String; bool get hasFutures => state.allParams.entries.any(isAsyncParam); Future completeFutures() => Future.wait( state.allParams.entries.where(isAsyncParam).map( (param) async { final doc = await asyncParams[param.key]!(param.value) .onError((_, __) => null); if (doc != null) { futureParamValues[param.key] = doc; return true; } return false; }, ), ).onError((_, __) => [false]).then((v) => v.every((e) => e)); dynamic getParam( String paramName, ParamType type, { bool isList = false, StructBuilder? structBuilder, }) { if (futureParamValues.containsKey(paramName)) { return futureParamValues[paramName]; } if (!state.allParams.containsKey(paramName)) { return null; } final param = state.allParams[paramName]; // Got parameter from `extras`, so just directly return it. if (param is! String) { return param; } // Return serialized value. return deserializeParam( param, type, isList, structBuilder: structBuilder, ); } } class FFRoute { const FFRoute({ required this.name, required this.path, required this.builder, this.requireAuth = false, this.asyncParams = const {}, this.routes = const [], }); final String name; final String path; final bool requireAuth; final Map Function(String)> asyncParams; final Widget Function(BuildContext, FFParameters) builder; final List routes; GoRoute toRoute(AppStateNotifier appStateNotifier) => GoRoute( name: name, path: path, redirect: (context, state) { if (appStateNotifier.shouldRedirect) { final redirectLocation = appStateNotifier.getRedirectLocation(); appStateNotifier.clearRedirectLocation(); return redirectLocation; } if (requireAuth && !appStateNotifier.loggedIn) { appStateNotifier.setRedirectLocationIfUnset(state.uri.toString()); return '/home'; } return null; }, pageBuilder: (context, state) { fixStatusBarOniOS16AndBelow(context); final ffParams = FFParameters(state, asyncParams); final page = ffParams.hasFutures ? FutureBuilder( future: ffParams.completeFutures(), builder: (context, _) => builder(context, ffParams), ) : builder(context, ffParams); final child = appStateNotifier.loading ? Center( child: SizedBox( width: 80.0, height: 80.0, child: SpinKitFadingCircle( color: FlutterFlowTheme.of(context).primary, size: 80.0, ), ), ) : page; final transitionInfo = state.transitionInfo; return transitionInfo.hasTransition ? CustomTransitionPage( key: state.pageKey, name: state.name, child: child, transitionDuration: transitionInfo.duration, transitionsBuilder: (context, animation, secondaryAnimation, child) => PageTransition( type: transitionInfo.transitionType, duration: transitionInfo.duration, reverseDuration: transitionInfo.duration, alignment: transitionInfo.alignment, child: child, ).buildTransitions( context, animation, secondaryAnimation, child, ), ) : MaterialPage( key: state.pageKey, name: state.name, child: child); }, routes: routes, ); } class TransitionInfo { const TransitionInfo({ required this.hasTransition, this.transitionType = PageTransitionType.fade, this.duration = const Duration(milliseconds: 300), this.alignment, }); final bool hasTransition; final PageTransitionType transitionType; final Duration duration; final Alignment? alignment; static TransitionInfo appDefault() => TransitionInfo(hasTransition: false); } class RootPageContext { const RootPageContext(this.isRootPage, [this.errorRoute]); final bool isRootPage; final String? errorRoute; static bool isInactiveRootPage(BuildContext context) { final rootPageContext = context.read(); final isRootPage = rootPageContext?.isRootPage ?? false; final location = GoRouterState.of(context).uri.toString(); return isRootPage && location != '/' && location != rootPageContext?.errorRoute; } static Widget wrap(Widget child, {String? errorRoute}) => Provider.value( value: RootPageContext(true, errorRoute), child: child, ); } extension GoRouterLocationExtension on GoRouter { String getCurrentLocation() { final RouteMatch lastMatch = routerDelegate.currentConfiguration.last; final RouteMatchList matchList = lastMatch is ImperativeRouteMatch ? lastMatch.matches : routerDelegate.currentConfiguration; return matchList.uri.toString(); } }