first commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../../../get.dart';
|
||||
|
||||
class GetInformationParser extends RouteInformationParser<GetNavConfig> {
|
||||
final String initialRoute;
|
||||
|
||||
GetInformationParser({
|
||||
this.initialRoute = '/',
|
||||
}) {
|
||||
Get.log('GetInformationParser is created !');
|
||||
}
|
||||
@override
|
||||
SynchronousFuture<GetNavConfig> parseRouteInformation(
|
||||
RouteInformation routeInformation,
|
||||
) {
|
||||
var location = routeInformation.location;
|
||||
if (location == '/') {
|
||||
//check if there is a corresponding page
|
||||
//if not, relocate to initialRoute
|
||||
if (!Get.routeTree.routes.any((element) => element.name == '/')) {
|
||||
location = initialRoute;
|
||||
}
|
||||
}
|
||||
|
||||
Get.log('GetInformationParser: route location: $location');
|
||||
|
||||
final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
|
||||
|
||||
return SynchronousFuture(
|
||||
GetNavConfig(
|
||||
currentTreeBranch: matchResult.treeBranch,
|
||||
location: location,
|
||||
state: routeInformation.state,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
RouteInformation restoreRouteInformation(GetNavConfig configuration) {
|
||||
return RouteInformation(
|
||||
location: configuration.location,
|
||||
state: configuration.state,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../../../get.dart';
|
||||
|
||||
// class GetRouterState extends GetxController {
|
||||
// GetRouterState({required this.currentTreeBranch});
|
||||
// final List<GetPage> currentTreeBranch;
|
||||
// GetPage? get currentPage => currentTreeBranch.last;
|
||||
|
||||
// static GetNavConfig? fromRoute(String route) {
|
||||
// final res = Get.routeTree.matchRoute(route);
|
||||
// if (res.treeBranch.isEmpty) return null;
|
||||
// return GetNavConfig(
|
||||
// currentTreeBranch: res.treeBranch,
|
||||
// location: route,
|
||||
// state: null,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
/// This config enables us to navigate directly to a sub-url
|
||||
class GetNavConfig extends RouteInformation {
|
||||
final List<GetPage> currentTreeBranch;
|
||||
GetPage? get currentPage => currentTreeBranch.last;
|
||||
|
||||
GetNavConfig({
|
||||
required this.currentTreeBranch,
|
||||
required String? location,
|
||||
required Object? state,
|
||||
}) : super(
|
||||
location: location,
|
||||
state: state,
|
||||
);
|
||||
|
||||
GetNavConfig copyWith({
|
||||
List<GetPage>? currentTreeBranch,
|
||||
required String? location,
|
||||
required Object? state,
|
||||
}) {
|
||||
return GetNavConfig(
|
||||
currentTreeBranch: currentTreeBranch ?? this.currentTreeBranch,
|
||||
location: location ?? this.location,
|
||||
state: state ?? this.state,
|
||||
);
|
||||
}
|
||||
|
||||
static GetNavConfig? fromRoute(String route) {
|
||||
final res = Get.routeTree.matchRoute(route);
|
||||
if (res.treeBranch.isEmpty) return null;
|
||||
return GetNavConfig(
|
||||
currentTreeBranch: res.treeBranch,
|
||||
location: route,
|
||||
state: null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => '''
|
||||
======GetNavConfig=====\ncurrentTreeBranch: $currentTreeBranch\ncurrentPage: $currentPage\n======GetNavConfig=====''';
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../get.dart';
|
||||
import '../../../get_state_manager/src/simple/list_notifier.dart';
|
||||
|
||||
class GetDelegate extends RouterDelegate<GetNavConfig>
|
||||
with ListenableMixin, ListNotifierMixin {
|
||||
final List<GetNavConfig> history = <GetNavConfig>[];
|
||||
final PopMode backButtonPopMode;
|
||||
final PreventDuplicateHandlingMode preventDuplicateHandlingMode;
|
||||
|
||||
final GetPage notFoundRoute;
|
||||
|
||||
final List<NavigatorObserver>? navigatorObservers;
|
||||
final TransitionDelegate<dynamic>? transitionDelegate;
|
||||
|
||||
final _allCompleters = <GetPage, Completer>{};
|
||||
|
||||
GetDelegate({
|
||||
GetPage? notFoundRoute,
|
||||
this.navigatorObservers,
|
||||
this.transitionDelegate,
|
||||
this.backButtonPopMode = PopMode.History,
|
||||
this.preventDuplicateHandlingMode =
|
||||
PreventDuplicateHandlingMode.ReorderRoutes,
|
||||
}) : notFoundRoute = notFoundRoute ??
|
||||
GetPage(
|
||||
name: '/404',
|
||||
page: () => const Scaffold(
|
||||
body: Text('Route not found'),
|
||||
),
|
||||
) {
|
||||
Get.log('GetDelegate is created !');
|
||||
}
|
||||
|
||||
@override
|
||||
GetNavConfig? get currentConfiguration {
|
||||
if (history.isEmpty) return null;
|
||||
final route = history.last;
|
||||
return route;
|
||||
}
|
||||
|
||||
GlobalKey<NavigatorState> get navigatorKey => Get.key;
|
||||
|
||||
Map<String, String> get parameters {
|
||||
return currentConfiguration?.currentPage?.parameters ?? {};
|
||||
}
|
||||
|
||||
T arguments<T>() {
|
||||
return currentConfiguration?.currentPage?.arguments as T;
|
||||
}
|
||||
|
||||
/// Removes routes according to [PopMode]
|
||||
/// until it reaches the specifc [fullRoute],
|
||||
/// DOES NOT remove the [fullRoute]
|
||||
Future<void> backUntil(
|
||||
String fullRoute, {
|
||||
PopMode popMode = PopMode.Page,
|
||||
}) async {
|
||||
// remove history or page entries until you meet route
|
||||
var iterator = currentConfiguration;
|
||||
while (_canPop(popMode) &&
|
||||
iterator != null &&
|
||||
iterator.location != fullRoute) {
|
||||
await _pop(popMode);
|
||||
// replace iterator
|
||||
iterator = currentConfiguration;
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pages = getVisualPages();
|
||||
if (pages.isEmpty) return const SizedBox.shrink();
|
||||
final extraObservers = navigatorObservers;
|
||||
return GetNavigator(
|
||||
key: navigatorKey,
|
||||
onPopPage: _onPopVisualRoute,
|
||||
pages: pages,
|
||||
observers: [
|
||||
GetObserver(),
|
||||
if (extraObservers != null) ...extraObservers,
|
||||
],
|
||||
transitionDelegate:
|
||||
transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
|
||||
);
|
||||
}
|
||||
|
||||
// void _unsafeHistoryClear() {
|
||||
// history.clear();
|
||||
// }
|
||||
|
||||
Future<bool> canPopHistory() {
|
||||
return SynchronousFuture(_canPopHistory());
|
||||
}
|
||||
|
||||
Future<bool> canPopPage() {
|
||||
return SynchronousFuture(_canPopPage());
|
||||
}
|
||||
|
||||
/// gets the visual pages from the current history entry
|
||||
///
|
||||
/// visual pages must have [participatesInRootNavigator] set to true
|
||||
List<GetPage> getVisualPages() {
|
||||
final currentHistory = currentConfiguration;
|
||||
if (currentHistory == null) return <GetPage>[];
|
||||
|
||||
final res = currentHistory.currentTreeBranch
|
||||
.where((r) => r.participatesInRootNavigator != null);
|
||||
if (res.isEmpty) {
|
||||
//default behavoir, all routes participate in root navigator
|
||||
return history.map((e) => e.currentPage!).toList();
|
||||
} else {
|
||||
//user specified at least one participatesInRootNavigator
|
||||
return res
|
||||
.where((element) => element.participatesInRootNavigator == true)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
// GetPageRoute getPageRoute(RouteSettings? settings) {
|
||||
// return PageRedirect(settings ?? RouteSettings(name: '/404'), _notFound())
|
||||
// .page();
|
||||
// }
|
||||
|
||||
Future<bool> handlePopupRoutes({
|
||||
Object? result,
|
||||
}) async {
|
||||
Route? currentRoute;
|
||||
navigatorKey.currentState!.popUntil((route) {
|
||||
currentRoute = route;
|
||||
return true;
|
||||
});
|
||||
if (currentRoute is PopupRoute) {
|
||||
return await navigatorKey.currentState!.maybePop(result);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<T?>? offAndToNamed<T>(
|
||||
String page, {
|
||||
dynamic arguments,
|
||||
int? id,
|
||||
dynamic result,
|
||||
Map<String, String>? parameters,
|
||||
PopMode popMode = PopMode.History,
|
||||
}) async {
|
||||
if (parameters != null) {
|
||||
final uri = Uri(path: page, queryParameters: parameters);
|
||||
page = uri.toString();
|
||||
}
|
||||
|
||||
await popRoute(result: result);
|
||||
return toNamed(page, arguments: arguments, parameters: parameters);
|
||||
}
|
||||
|
||||
Future<T> offNamed<T>(
|
||||
String page, {
|
||||
dynamic arguments,
|
||||
Map<String, String>? parameters,
|
||||
}) async {
|
||||
history.removeLast();
|
||||
return toNamed<T>(page, arguments: arguments, parameters: parameters);
|
||||
}
|
||||
|
||||
Future<GetNavConfig?> popHistory() async {
|
||||
return await _popHistory();
|
||||
}
|
||||
|
||||
// returns the popped page
|
||||
@override
|
||||
Future<bool> popRoute({
|
||||
Object? result,
|
||||
PopMode popMode = PopMode.Page,
|
||||
}) async {
|
||||
//Returning false will cause the entire app to be popped.
|
||||
final wasPopup = await handlePopupRoutes(result: result);
|
||||
if (wasPopup) return true;
|
||||
final popped = await _pop(popMode);
|
||||
refresh();
|
||||
if (popped != null) {
|
||||
//emulate the old pop with result
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Adds a new history entry and waits for the result
|
||||
Future<void> pushHistory(
|
||||
GetNavConfig config, {
|
||||
bool rebuildStack = true,
|
||||
}) async {
|
||||
//this changes the currentConfiguration
|
||||
await _pushHistory(config);
|
||||
if (rebuildStack) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
Future<GetNavConfig?> runMiddleware(GetNavConfig config) async {
|
||||
final middlewares = config.currentTreeBranch.last.middlewares;
|
||||
if (middlewares == null) {
|
||||
return config;
|
||||
}
|
||||
var iterator = config;
|
||||
for (var item in middlewares) {
|
||||
var redirectRes = await item.redirectDelegate(iterator);
|
||||
if (redirectRes == null) return null;
|
||||
iterator = redirectRes;
|
||||
}
|
||||
return iterator;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setNewRoutePath(GetNavConfig configuration) async {
|
||||
await pushHistory(configuration);
|
||||
}
|
||||
|
||||
Future<T> toNamed<T>(
|
||||
String page, {
|
||||
dynamic arguments,
|
||||
Map<String, String>? parameters,
|
||||
}) async {
|
||||
if (parameters != null) {
|
||||
final uri = Uri(path: page, queryParameters: parameters);
|
||||
page = uri.toString();
|
||||
}
|
||||
|
||||
final decoder = Get.routeTree.matchRoute(page, arguments: arguments);
|
||||
decoder.replaceArguments(arguments);
|
||||
|
||||
final completer = Completer<T>();
|
||||
|
||||
if (decoder.route != null) {
|
||||
_allCompleters[decoder.route!] = completer;
|
||||
await pushHistory(
|
||||
GetNavConfig(
|
||||
currentTreeBranch: decoder.treeBranch,
|
||||
location: page,
|
||||
state: null, //TODO: persist state?
|
||||
),
|
||||
);
|
||||
|
||||
return completer.future;
|
||||
} else {
|
||||
///TODO: IMPLEMENT ROUTE NOT FOUND
|
||||
|
||||
return Future.value();
|
||||
}
|
||||
}
|
||||
|
||||
bool _canPop(PopMode mode) {
|
||||
switch (mode) {
|
||||
case PopMode.History:
|
||||
return _canPopHistory();
|
||||
case PopMode.Page:
|
||||
default:
|
||||
return _canPopPage();
|
||||
}
|
||||
}
|
||||
|
||||
bool _canPopHistory() {
|
||||
return history.length > 1;
|
||||
}
|
||||
|
||||
bool _canPopPage() {
|
||||
final currentTreeBranch = currentConfiguration?.currentTreeBranch;
|
||||
if (currentTreeBranch == null) return false;
|
||||
return currentTreeBranch.length > 1 ? true : _canPopHistory();
|
||||
}
|
||||
|
||||
Future<GetNavConfig?> _doPopHistory() async {
|
||||
return await _unsafeHistoryRemoveAt(history.length - 1);
|
||||
}
|
||||
|
||||
// @override
|
||||
// Future<void> setInitialRoutePath(GetNavConfig configuration) async {
|
||||
// //no need to clear history with Reorder route strategy
|
||||
// // _unsafeHistoryClear();
|
||||
// // _resultCompleter.clear();
|
||||
// await pushHistory(configuration);
|
||||
// }
|
||||
|
||||
Future<GetNavConfig?> _doPopPage() async {
|
||||
final currentBranch = currentConfiguration?.currentTreeBranch;
|
||||
if (currentBranch != null && currentBranch.length > 1) {
|
||||
//remove last part only
|
||||
final remaining = currentBranch.take(currentBranch.length - 1);
|
||||
final prevHistoryEntry =
|
||||
history.length > 1 ? history[history.length - 2] : null;
|
||||
|
||||
//check if current route is the same as the previous route
|
||||
if (prevHistoryEntry != null) {
|
||||
//if so, pop the entire history entry
|
||||
final newLocation = remaining.last.name;
|
||||
final prevLocation = prevHistoryEntry.location;
|
||||
if (newLocation == prevLocation) {
|
||||
//pop the entire history entry
|
||||
return await _popHistory();
|
||||
}
|
||||
}
|
||||
|
||||
//create a new route with the remaining tree branch
|
||||
final res = await _popHistory();
|
||||
await _pushHistory(
|
||||
GetNavConfig(
|
||||
currentTreeBranch: remaining.toList(),
|
||||
location: remaining.last.name,
|
||||
state: null, //TOOD: persist state??
|
||||
),
|
||||
);
|
||||
return res;
|
||||
} else {
|
||||
//remove entire entry
|
||||
return await _popHistory();
|
||||
}
|
||||
}
|
||||
|
||||
bool _onPopVisualRoute(Route<dynamic> route, dynamic result) {
|
||||
final didPop = route.didPop(result);
|
||||
if (!didPop) {
|
||||
return false;
|
||||
}
|
||||
final settings = route.settings;
|
||||
if (settings is GetPage) {
|
||||
final config = history.cast<GetNavConfig?>().firstWhere(
|
||||
(element) => element?.currentPage == settings,
|
||||
orElse: () => null,
|
||||
);
|
||||
if (config != null) {
|
||||
_removeHistoryEntry(config);
|
||||
}
|
||||
if (_allCompleters.containsKey(settings)) {
|
||||
_allCompleters[settings]?.complete(route.popped);
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<GetNavConfig?> _pop(PopMode mode) async {
|
||||
switch (mode) {
|
||||
case PopMode.History:
|
||||
return await _popHistory();
|
||||
case PopMode.Page:
|
||||
return await _popPage();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<GetNavConfig?> _popHistory() async {
|
||||
if (!_canPopHistory()) return null;
|
||||
return await _doPopHistory();
|
||||
}
|
||||
|
||||
Future<GetNavConfig?> _popPage() async {
|
||||
if (!_canPopPage()) return null;
|
||||
return await _doPopPage();
|
||||
}
|
||||
|
||||
Future<void> _pushHistory(GetNavConfig config) async {
|
||||
if (config.currentPage!.preventDuplicates) {
|
||||
final originalEntryIndex =
|
||||
history.indexWhere((element) => element.location == config.location);
|
||||
if (originalEntryIndex >= 0) {
|
||||
switch (preventDuplicateHandlingMode) {
|
||||
case PreventDuplicateHandlingMode.PopUntilOriginalRoute:
|
||||
await backUntil(config.location!, popMode: PopMode.Page);
|
||||
break;
|
||||
case PreventDuplicateHandlingMode.ReorderRoutes:
|
||||
await _unsafeHistoryRemoveAt(originalEntryIndex);
|
||||
await _unsafeHistoryAdd(config);
|
||||
break;
|
||||
case PreventDuplicateHandlingMode.DoNothing:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
await _unsafeHistoryAdd(config);
|
||||
}
|
||||
|
||||
Future<void> _removeHistoryEntry(GetNavConfig entry) async {
|
||||
await _unsafeHistoryRemove(entry);
|
||||
}
|
||||
|
||||
Future<void> _unsafeHistoryAdd(GetNavConfig config) async {
|
||||
final res = await runMiddleware(config);
|
||||
if (res == null) return;
|
||||
history.add(res);
|
||||
}
|
||||
|
||||
Future<void> _unsafeHistoryRemove(GetNavConfig config) async {
|
||||
var index = history.indexOf(config);
|
||||
if (index >= 0) await _unsafeHistoryRemoveAt(index);
|
||||
}
|
||||
|
||||
Future<GetNavConfig?> _unsafeHistoryRemoveAt(int index) async {
|
||||
if (index == history.length - 1 && history.length > 1) {
|
||||
//removing WILL update the current route
|
||||
final toCheck = history[history.length - 2];
|
||||
final resMiddleware = await runMiddleware(toCheck);
|
||||
if (resMiddleware == null) return null;
|
||||
history[history.length - 2] = resMiddleware;
|
||||
}
|
||||
return history.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
class GetNavigator extends Navigator {
|
||||
GetNavigator({
|
||||
GlobalKey<NavigatorState>? key,
|
||||
bool Function(Route<dynamic>, dynamic)? onPopPage,
|
||||
required List<Page> pages,
|
||||
List<NavigatorObserver>? observers,
|
||||
bool reportsRouteUpdateToEngine = false,
|
||||
TransitionDelegate? transitionDelegate,
|
||||
}) : super(
|
||||
//keys should be optional
|
||||
key: key,
|
||||
onPopPage: onPopPage ??
|
||||
(route, result) {
|
||||
final didPop = route.didPop(result);
|
||||
if (!didPop) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
|
||||
pages: pages,
|
||||
observers: [
|
||||
// GetObserver(),
|
||||
if (observers != null) ...observers,
|
||||
],
|
||||
transitionDelegate:
|
||||
transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Enables the user to customize the intended pop behavior
|
||||
///
|
||||
/// Goes to either the previous history entry or the previous page entry
|
||||
///
|
||||
/// e.g. if the user navigates to these pages
|
||||
/// 1) /home
|
||||
/// 2) /home/products/1234
|
||||
///
|
||||
/// when popping on [History] mode, it will emulate a browser back button.
|
||||
///
|
||||
/// so the new history stack will be:
|
||||
/// 1) /home
|
||||
///
|
||||
/// when popping on [Page] mode, it will only remove the last part of the route
|
||||
/// so the new history stack will be:
|
||||
/// 1) /home
|
||||
/// 2) /home/products
|
||||
///
|
||||
/// another pop will change the history stack to:
|
||||
/// 1) /home
|
||||
enum PopMode {
|
||||
History,
|
||||
Page,
|
||||
}
|
||||
|
||||
/// Enables the user to customize the behavior when pushing multiple routes that
|
||||
/// shouldn't be duplicates
|
||||
enum PreventDuplicateHandlingMode {
|
||||
/// Removes the history entries until it reaches the old route
|
||||
PopUntilOriginalRoute,
|
||||
|
||||
/// Simply don't push the new route
|
||||
DoNothing,
|
||||
|
||||
/// Recommended - Moves the old route entry to the front
|
||||
///
|
||||
/// With this mode, you guarantee there will be only one
|
||||
/// route entry for each location
|
||||
ReorderRoutes
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../get.dart';
|
||||
|
||||
class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
|
||||
extends StatefulWidget {
|
||||
final TDelegate routerDelegate;
|
||||
final Widget Function(
|
||||
BuildContext context,
|
||||
TDelegate delegate,
|
||||
T? currentRoute,
|
||||
) builder;
|
||||
|
||||
//keys
|
||||
RouterOutlet.builder({
|
||||
Key? key,
|
||||
TDelegate? delegate,
|
||||
required this.builder,
|
||||
}) : routerDelegate = delegate ?? Get.delegate<TDelegate, T>()!,
|
||||
super(key: key);
|
||||
|
||||
RouterOutlet({
|
||||
Key? key,
|
||||
TDelegate? delegate,
|
||||
required Iterable<GetPage> Function(T currentNavStack) pickPages,
|
||||
required Widget Function(
|
||||
BuildContext context,
|
||||
TDelegate,
|
||||
Iterable<GetPage>? page,
|
||||
)
|
||||
pageBuilder,
|
||||
}) : this.builder(
|
||||
builder: (context, rDelegate, currentConfig) {
|
||||
var picked =
|
||||
currentConfig == null ? null : pickPages(currentConfig);
|
||||
if (picked?.isEmpty ?? false) {
|
||||
picked = null;
|
||||
}
|
||||
return pageBuilder(context, rDelegate, picked);
|
||||
},
|
||||
delegate: delegate,
|
||||
);
|
||||
@override
|
||||
RouterOutletState<TDelegate, T> createState() =>
|
||||
RouterOutletState<TDelegate, T>();
|
||||
}
|
||||
|
||||
class RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>
|
||||
extends State<RouterOutlet<TDelegate, T>> {
|
||||
TDelegate get delegate => widget.routerDelegate;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getCurrentRoute();
|
||||
delegate.addListener(onRouterDelegateChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
delegate.removeListener(onRouterDelegateChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
T? currentRoute;
|
||||
void _getCurrentRoute() {
|
||||
currentRoute = delegate.currentConfiguration;
|
||||
}
|
||||
|
||||
void onRouterDelegateChanged() {
|
||||
setState(_getCurrentRoute);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return widget.builder(context, delegate, currentRoute);
|
||||
}
|
||||
}
|
||||
|
||||
class GetRouterOutlet extends RouterOutlet<GetDelegate, GetNavConfig> {
|
||||
GetRouterOutlet({
|
||||
String? anchorRoute,
|
||||
required String initialRoute,
|
||||
Iterable<GetPage> Function(Iterable<GetPage> afterAnchor)? filterPages,
|
||||
GlobalKey<NavigatorState>? key,
|
||||
GetDelegate? delegate,
|
||||
}) : this.pickPages(
|
||||
pickPages: (config) {
|
||||
Iterable<GetPage<dynamic>> ret;
|
||||
if (anchorRoute == null) {
|
||||
// jump the ancestor path
|
||||
final length = Uri.parse(initialRoute).pathSegments.length;
|
||||
|
||||
return config.currentTreeBranch
|
||||
.skip(length)
|
||||
.take(length)
|
||||
.toList();
|
||||
}
|
||||
ret = config.currentTreeBranch.pickAfterRoute(anchorRoute);
|
||||
if (filterPages != null) {
|
||||
ret = filterPages(ret);
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
emptyPage: (delegate) =>
|
||||
Get.routeTree.matchRoute(initialRoute).route ??
|
||||
delegate.notFoundRoute,
|
||||
key: key,
|
||||
delegate: delegate,
|
||||
);
|
||||
GetRouterOutlet.pickPages({
|
||||
Widget Function(GetDelegate delegate)? emptyWidget,
|
||||
GetPage Function(GetDelegate delegate)? emptyPage,
|
||||
required Iterable<GetPage> Function(GetNavConfig currentNavStack) pickPages,
|
||||
bool Function(Route<dynamic>, dynamic)? onPopPage,
|
||||
GlobalKey<NavigatorState>? key,
|
||||
GetDelegate? delegate,
|
||||
}) : super(
|
||||
pageBuilder: (context, rDelegate, pages) {
|
||||
final pageRes = <GetPage?>[
|
||||
...?pages,
|
||||
if (pages == null || pages.isEmpty) emptyPage?.call(rDelegate),
|
||||
].whereType<GetPage>();
|
||||
|
||||
if (pageRes.isNotEmpty) {
|
||||
return GetNavigator(
|
||||
onPopPage: onPopPage ??
|
||||
(route, result) {
|
||||
final didPop = route.didPop(result);
|
||||
if (!didPop) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
pages: pageRes.toList(),
|
||||
key: key,
|
||||
);
|
||||
}
|
||||
return (emptyWidget?.call(rDelegate) ?? const SizedBox.shrink());
|
||||
},
|
||||
pickPages: pickPages,
|
||||
delegate: delegate ?? Get.rootDelegate,
|
||||
);
|
||||
|
||||
GetRouterOutlet.builder({
|
||||
required Widget Function(
|
||||
BuildContext context,
|
||||
GetDelegate delegate,
|
||||
GetNavConfig? currentRoute,
|
||||
)
|
||||
builder,
|
||||
GetDelegate? routerDelegate,
|
||||
}) : super.builder(
|
||||
builder: builder,
|
||||
delegate: routerDelegate,
|
||||
);
|
||||
}
|
||||
|
||||
extension PagesListExt on List<GetPage> {
|
||||
Iterable<GetPage> pickAtRoute(String route) {
|
||||
return skipWhile((value) {
|
||||
return value.name != route;
|
||||
});
|
||||
}
|
||||
|
||||
Iterable<GetPage> pickAfterRoute(String route) {
|
||||
return pickAtRoute(route).skip(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user