first commit
This commit is contained in:
686
lib/flutterlib/nav/nav.dart
Normal file
686
lib/flutterlib/nav/nav.dart
Normal file
@@ -0,0 +1,686 @@
|
||||
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,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user