687 lines
22 KiB
Dart
687 lines
22 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:page_transition/page_transition.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
import '/backend/schema/enums/enums.dart';
|
|
|
|
import '/auth/custom_auth/custom_auth_user_provider.dart';
|
|
|
|
import '/index.dart';
|
|
import '/main.dart';
|
|
import '/flutterlib/flutter_theme.dart';
|
|
import '/flutterlib/lat_lng.dart';
|
|
import '/flutterlib/place.dart';
|
|
import '/flutterlib/flutter_util.dart';
|
|
import 'serialization_util.dart';
|
|
|
|
export 'package:go_router/go_router.dart';
|
|
export 'serialization_util.dart';
|
|
|
|
const kTransitionInfoKey = '__transition_info__';
|
|
|
|
class AppStateNotifier extends ChangeNotifier {
|
|
AppStateNotifier._();
|
|
|
|
static AppStateNotifier? _instance;
|
|
static AppStateNotifier get instance => _instance ??= AppStateNotifier._();
|
|
|
|
NumstationAuthUser? initialUser;
|
|
NumstationAuthUser? 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(NumstationAuthUser 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,
|
|
errorBuilder: (context, state) =>
|
|
appStateNotifier.loggedIn ? MenuWidget() : LoginWidget(),
|
|
routes: [
|
|
FFRoute(
|
|
name: '_initialize',
|
|
path: '/',
|
|
builder: (context, _) =>
|
|
appStateNotifier.loggedIn ? MenuWidget() : LoginWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'login',
|
|
path: '/login',
|
|
builder: (context, params) => LoginWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'signup',
|
|
path: '/signup',
|
|
builder: (context, params) => SignupWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'login1',
|
|
path: '/login1',
|
|
builder: (context, params) => Login1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'login2',
|
|
path: '/login2',
|
|
builder: (context, params) => Login2Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'login3',
|
|
path: '/login3',
|
|
builder: (context, params) => Login3Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'login4',
|
|
path: '/login4',
|
|
builder: (context, params) => Login4Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'login5',
|
|
path: '/login5',
|
|
builder: (context, params) => Login5Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'tnc',
|
|
path: '/tnc',
|
|
builder: (context, params) => TncWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'policy',
|
|
path: '/policy',
|
|
builder: (context, params) => PolicyWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'menu',
|
|
path: '/menu',
|
|
builder: (context, params) => MenuWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'dashboard',
|
|
path: '/dashboard',
|
|
builder: (context, params) => DashboardWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'test',
|
|
path: '/test',
|
|
builder: (context, params) => TestWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'setting',
|
|
path: '/setting',
|
|
builder: (context, params) => SettingWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'user',
|
|
path: '/user',
|
|
builder: (context, params) => UserWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk1',
|
|
path: '/bk1',
|
|
builder: (context, params) => Bk1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'enquiry',
|
|
path: '/enquiry',
|
|
builder: (context, params) => EnquiryWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'myenquiry',
|
|
path: '/myenquiry',
|
|
builder: (context, params) => MyenquiryWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'myenquiry1',
|
|
path: '/myenquiry1',
|
|
builder: (context, params) => Myenquiry1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'language',
|
|
path: '/language',
|
|
builder: (context, params) => LanguageWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'account1',
|
|
path: '/account1',
|
|
builder: (context, params) => Account1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'chatbox',
|
|
path: '/chatbox',
|
|
builder: (context, params) => ChatboxWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec',
|
|
path: '/compsec',
|
|
builder: (context, params) => CompsecWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec1',
|
|
path: '/compsec1',
|
|
builder: (context, params) => Compsec1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec2',
|
|
path: '/compsec2',
|
|
builder: (context, params) => Compsec2Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec3',
|
|
path: '/compsec3',
|
|
builder: (context, params) => Compsec3Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec4',
|
|
path: '/compsec4',
|
|
builder: (context, params) => Compsec4Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec5',
|
|
path: '/compsec5',
|
|
builder: (context, params) => Compsec5Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk2',
|
|
path: '/bk2',
|
|
builder: (context, params) => Bk2Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk3',
|
|
path: '/bk3',
|
|
builder: (context, params) => Bk3Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk4',
|
|
path: '/bk4',
|
|
builder: (context, params) => Bk4Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk4_1',
|
|
path: '/bk41',
|
|
builder: (context, params) => Bk41Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk4_2',
|
|
path: '/bk42',
|
|
builder: (context, params) => Bk42Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'search',
|
|
path: '/search',
|
|
builder: (context, params) => SearchWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk_checkout',
|
|
path: '/bkCheckout',
|
|
builder: (context, params) => BkCheckoutWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'bk_checkout1',
|
|
path: '/bkCheckout1',
|
|
builder: (context, params) => BkCheckout1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_checkout',
|
|
path: '/compsecCheckout',
|
|
builder: (context, params) => CompsecCheckoutWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_checkout1',
|
|
path: '/compsecCheckout1',
|
|
builder: (context, params) => CompsecCheckout1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_checkout2',
|
|
path: '/compsecCheckout2',
|
|
builder: (context, params) => CompsecCheckout2Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsecEnq',
|
|
path: '/compsecEnq',
|
|
builder: (context, params) => CompsecEnqWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsecEnq1',
|
|
path: '/compsecEnq1',
|
|
builder: (context, params) => CompsecEnq1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_changename',
|
|
path: '/compsecChangename',
|
|
builder: (context, params) => CompsecChangenameWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_changeaddress',
|
|
path: '/compsecChangeaddress',
|
|
builder: (context, params) => CompsecChangeaddressWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_changedirector',
|
|
path: '/compsecChangedirector',
|
|
builder: (context, params) => CompsecChangedirectorWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_changesecretary',
|
|
path: '/compsecChangesecretary',
|
|
builder: (context, params) => CompsecChangesecretaryWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_changesecrORdir',
|
|
path: '/compsecChangesecrORdir',
|
|
builder: (context, params) => CompsecChangesecrORdirWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_resignation',
|
|
path: '/compsecResignation',
|
|
builder: (context, params) => CompsecResignationWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_transferofShares',
|
|
path: '/compsecTransferofShares',
|
|
builder: (context, params) => CompsecTransferofSharesWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsec_otherRequest',
|
|
path: '/compsecOtherRequest',
|
|
builder: (context, params) => CompsecOtherRequestWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'account',
|
|
path: '/account',
|
|
builder: (context, params) => AccountWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'notification',
|
|
path: '/notification',
|
|
builder: (context, params) => NotificationWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsecQueue',
|
|
path: '/compsecQueue',
|
|
builder: (context, params) => CompsecQueueWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsecQueue1_1',
|
|
path: '/compsecQueue11',
|
|
builder: (context, params) => CompsecQueue11Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'testing',
|
|
path: '/testing',
|
|
builder: (context, params) => TestingWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'newuser',
|
|
path: '/newuser',
|
|
builder: (context, params) => NewuserWidget(
|
|
checkPermission23:
|
|
params.getParam('checkPermission23', ParamType.bool),
|
|
checkPremission22:
|
|
params.getParam('checkPremission22', ParamType.bool),
|
|
),
|
|
),
|
|
FFRoute(
|
|
name: 'userDetail',
|
|
path: '/userDetail',
|
|
builder: (context, params) => UserDetailWidget(
|
|
firstName: params.getParam('firstName', ParamType.String),
|
|
lastName: params.getParam('lastName', ParamType.String),
|
|
phone: params.getParam('phone', ParamType.int),
|
|
email: params.getParam('email', ParamType.String),
|
|
status: params.getParam('status', ParamType.String),
|
|
),
|
|
),
|
|
FFRoute(
|
|
name: 'compsecDigitalTrans_list',
|
|
path: '/compsecDigitalTransList',
|
|
builder: (context, params) => CompsecDigitalTransListWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'compsecServicedraft',
|
|
path: '/compsecServicedraft',
|
|
builder: (context, params) => CompsecServicedraftWidget(),
|
|
),
|
|
FFRoute(
|
|
name: 'setting1',
|
|
path: '/setting1',
|
|
builder: (context, params) => Setting1Widget(),
|
|
),
|
|
FFRoute(
|
|
name: 'editUser',
|
|
path: '/editUser',
|
|
builder: (context, params) => EditUserWidget(
|
|
firstName: params.getParam('firstName', ParamType.String),
|
|
lastName: params.getParam('lastName', ParamType.String),
|
|
phone: params.getParam('phone', ParamType.int),
|
|
email: params.getParam('email', ParamType.String),
|
|
userID: params.getParam('userID', ParamType.int),
|
|
checkPermission23:
|
|
params.getParam('checkPermission23', ParamType.bool),
|
|
checkPremission22:
|
|
params.getParam('checkPremission22', ParamType.bool),
|
|
roleID: params.getParam('roleID', ParamType.String),
|
|
),
|
|
),
|
|
FFRoute(
|
|
name: 'bk_view',
|
|
path: '/bkView',
|
|
builder: (context, params) => BkViewWidget(
|
|
fileUrl: params.getParam('fileUrl', ParamType.JSON),
|
|
),
|
|
),
|
|
FFRoute(
|
|
name: 'search1',
|
|
path: '/search1',
|
|
builder: (context, params) => Search1Widget(
|
|
search: params.getParam('search', ParamType.String),
|
|
status: params.getParam('status', ParamType.String),
|
|
category: params.getParam('category', ParamType.String),
|
|
fixDate: params.getParam('fixDate', ParamType.String),
|
|
dateFrom: params.getParam('dateFrom', ParamType.String),
|
|
dateTo: params.getParam('dateTo', ParamType.String),
|
|
),
|
|
),
|
|
FFRoute(
|
|
name: 'search_page',
|
|
path: '/searchPage',
|
|
builder: (context, params) => SearchPageWidget(),
|
|
)
|
|
].map((r) => r.toRoute(appStateNotifier)).toList(),
|
|
);
|
|
|
|
extension NavParamExtensions on Map<String, String?> {
|
|
Map<String, String> 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<String, String> pathParameters = const <String, String>{},
|
|
Map<String, String> queryParameters = const <String, String>{},
|
|
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<String, String> pathParameters = const <String, String>{},
|
|
Map<String, String> queryParameters = const <String, String>{},
|
|
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<String, dynamic> get extraMap =>
|
|
extra != null ? extra as Map<String, dynamic> : {};
|
|
Map<String, dynamic> get allParams => <String, dynamic>{}
|
|
..addAll(pathParameters)
|
|
..addAll(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<String, Future<dynamic> Function(String)> asyncParams;
|
|
|
|
Map<String, dynamic> 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.extraMap.length == 1 &&
|
|
state.extraMap.containsKey(kTransitionInfoKey));
|
|
bool isAsyncParam(MapEntry<String, dynamic> param) =>
|
|
asyncParams.containsKey(param.key) && param.value is String;
|
|
bool get hasFutures => state.allParams.entries.any(isAsyncParam);
|
|
Future<bool> 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<T>(
|
|
String paramName,
|
|
ParamType type, [
|
|
bool isList = false,
|
|
]) {
|
|
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<T>(
|
|
param,
|
|
type,
|
|
isList,
|
|
);
|
|
}
|
|
}
|
|
|
|
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<String, Future<dynamic> Function(String)> asyncParams;
|
|
final Widget Function(BuildContext, FFParameters) builder;
|
|
final List<GoRoute> 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.location);
|
|
return '/login';
|
|
}
|
|
return null;
|
|
},
|
|
pageBuilder: (context, state) {
|
|
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: 50.0,
|
|
height: 50.0,
|
|
child: CircularProgressIndicator(
|
|
valueColor: AlwaysStoppedAnimation<Color>(
|
|
FlutterTheme.of(context).info,
|
|
),
|
|
),
|
|
),
|
|
)
|
|
: page;
|
|
|
|
final transitionInfo = state.transitionInfo;
|
|
return transitionInfo.hasTransition
|
|
? CustomTransitionPage(
|
|
key: state.pageKey,
|
|
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, 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<RootPageContext?>();
|
|
final isRootPage = rootPageContext?.isRootPage ?? false;
|
|
final location = GoRouter.of(context).location;
|
|
return isRootPage &&
|
|
location != '/' &&
|
|
location != rootPageContext?.errorRoute;
|
|
}
|
|
|
|
static Widget wrap(Widget child, {String? errorRoute}) => Provider.value(
|
|
value: RootPageContext(true, errorRoute),
|
|
child: child,
|
|
);
|
|
}
|